Commit 72c56b8e authored by John Doe's avatar John Doe
Browse files

Upload Client.

parent 13d5f931
Pipeline #6 canceled with stages
PRIVATE_KEY=
INFURA_PROJECT_ID=
COINMARKETCAP_API_KEY=
ETHERSCAN_API_KEY=
BSC_API_KEY=
\ No newline at end of file
# Pilot Client
# README #
This README would normally document whatever steps are necessary to get your application up and running.
### What is this repository for? ###
* Quick summary
* Version
* [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
### How do I get set up? ###
* Summary of set up
* Configuration
* Dependencies
* Database configuration
* How to run tests
* Deployment instructions
### Contribution guidelines ###
* Writing tests
* Code review
* Other guidelines
### Who do I talk to? ###
* Repo owner or admin
* Other community or team contact
\ No newline at end of file
module.exports = [
// "0x97c35747AbE05EFD38A1Fc081a42600fdfB1e2F1", // xft token address
// "0xA542a8Ed9E40eb6C39Dcc0b7d3293BA174C8DbE1", // price consumer address
];
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./SchnorrSignature.sol";
import "./interfaces/IERC20MintableBurnable.sol";
import "./interfaces/IPriceConsumer.sol";
contract CommitmentCircuit is SchnorrSignature {
using SafeERC20 for IERC20;
enum Assets {
XFT,
USD,
BTC,
ETH,
XAU
}
struct CommitmentDetails {
PointEC commitment;
Assets asset;
}
IERC20MintableBurnable public xftTokenAddress;
IPriceConsumer public priceConsumer;
event CommitmentTransferred(
address indexed sender,
address indexed recipient,
uint256 senderCommitmentId,
uint256 recipientCommitmentId,
PointEC senderCommitment,
PointEC recipientCommitment
);
event Deposited(
address indexed to,
uint256 amount,
uint256 indexed commitmentId,
PointEC commitment
);
event Withdrawn(
address indexed to,
uint256 amount,
uint256 indexed commitmentIdOld,
PointEC commitmentOld
);
event Excessed(address indexed to, uint256 indexed commitmentId, PointEC commitment);
event Grouped(address indexed to, uint256 indexed id, PointEC commitment);
// todo: public is temporary
mapping(address => uint256[]) public _idsByAddress;
mapping(address => mapping(uint256 => CommitmentDetails)) public _commitmentById;
mapping(address => mapping(uint256 => bool)) public _spents;
constructor(address _xftTokenAddress, address _priceConsumer) {
require(_xftTokenAddress != address(0), "Token address not be zero");
require(_priceConsumer != address(0), "Price consumer address not be zero");
xftTokenAddress = IERC20MintableBurnable(_xftTokenAddress);
priceConsumer = IPriceConsumer(_priceConsumer);
}
/**
* @dev Transfer commitment between users.
* @param recipient address of commitment recipient.
* @param senderCommitmentId id of the sending commitment.
* @param recipientCommitment new commitment that will be received by recipient:
commitment - new commitment
asset - asset of commitment.
* @param excessCommitment Commitment for excess amount.
* @param senderPubKey Sender's public key.
* @param recipientPubKey Recipient's public key.
* @param excessPubKey Public key for excess amount.
* @param schnorrSignatureSet Set of Schnorr params:
* message - Signed message
* pubKey - Public key with which message was signed
* ecR - Signature part R
* s - Signature part s.
*/
function complexTransferCommitment(
address recipient,
uint256 senderCommitmentId,
CommitmentDetails memory recipientCommitment,
PointEC memory excessCommitment,
PointEC memory senderPubKey,
PointEC memory recipientPubKey,
PointEC memory excessPubKey,
SlotSchnorrSignature memory schnorrSignatureSet
) public {
require(
SchnorrSignatureVerify(
schnorrSignatureSet.message,
schnorrSignatureSet.publicKey,
schnorrSignatureSet.ecR,
schnorrSignatureSet.s
),
"invalid signature"
);
CommitmentDetails memory senderCommitment = _commitmentById[msg.sender][
senderCommitmentId
];
require(senderCommitment.asset == recipientCommitment.asset, "Different assets");
require(!_spents[msg.sender][senderCommitmentId], "Commitment already used");
PointEC memory _ecVerify;
PointEC memory _ecSum;
(_ecVerify.x, _ecVerify.y) = eAdd(
recipientPubKey.x,
recipientPubKey.y,
excessPubKey.x,
excessPubKey.y
);
(_ecVerify.x, _ecVerify.y) = eSub(
senderPubKey.x,
senderPubKey.y,
_ecVerify.x,
_ecVerify.y
);
(_ecSum.x, _ecSum.y) = eAdd(
recipientCommitment.commitment.x,
recipientCommitment.commitment.y,
excessCommitment.x,
excessCommitment.y
);
require(
_CommitmentVerify(senderCommitment.commitment, _ecSum, _ecVerify),
"invalid commitments"
);
_spents[msg.sender][senderCommitmentId] = true;
uint256 _id = _CommitmentNewAdd(
recipient,
recipientCommitment.commitment,
recipientCommitment.asset
);
emit CommitmentTransferred(
msg.sender,
recipient,
senderCommitmentId,
_id,
senderCommitment.commitment,
recipientCommitment.commitment
);
_id = _CommitmentNewAdd(msg.sender, excessCommitment, recipientCommitment.asset);
emit Excessed(msg.sender, _id, excessCommitment);
}
/**
* @dev Deposit xft tokens and save commitment to user.
* @param amountIn amount of xft to be swapped.
* @param amountComm amount of zkAsset to be deposited.
* @param recipientCommitment new commitment that will be saved for user:
commitment - new commitment
asset - asset of commitment.
* @param schnorrSignatureSet Set of Schnorr params:
* message - Signed message
* pubKey - Public key with which message was signed
* ecR - Signature part R
* s - Signature part s.
*/
function deposit(
uint256 amountIn,
uint256 amountComm,
CommitmentDetails memory recipientCommitment,
SlotSchnorrSignature memory schnorrSignatureSet
) public {
require(amountIn != 0 && amountComm != 0, "Amount cannot be 0");
(uint256 currPrice, ) = priceConsumer.exchangeAssets(
uint8(recipientCommitment.asset),
uint8(Assets.XFT),
amountComm
);
require(amountIn == currPrice, "Incorrect input amount");
require(
SchnorrSignatureVerify(
schnorrSignatureSet.message,
schnorrSignatureSet.publicKey,
schnorrSignatureSet.ecR,
schnorrSignatureSet.s
),
"invalid signature"
);
PointEC memory ecH = _genPointEC(abi.encodePacked(gx, gy));
(uint256 x, uint256 y) = ePedersenCommitmentPK(
amountComm,
schnorrSignatureSet.publicKey.x,
schnorrSignatureSet.publicKey.y,
ecH.x,
ecH.y
);
require(
x == recipientCommitment.commitment.x && y == recipientCommitment.commitment.y,
"this amount cannot be deposited"
);
IERC20(xftTokenAddress).safeTransferFrom(msg.sender, address(this), amountIn);
xftTokenAddress.burn(amountIn);
uint256 id = _CommitmentNewAdd(
msg.sender,
recipientCommitment.commitment,
recipientCommitment.asset
);
emit Deposited(msg.sender, amountIn, id, _commitmentById[msg.sender][id].commitment);
}
/**
* @dev Withdraw xft tokens.
* @param amount of xft to be withdrawn.
* @param recipientCommitmentOldId id of the withdrawn commitment.
* @param schnorrSignatureSet Set of Schnorr params:
* message - Signed message
* pubKey - Public key with which message was signed
* ecR - Signature part R
* s - Signature part s.
*/
function withdraw(
uint256 amount,
uint256 recipientCommitmentOldId,
SlotSchnorrSignature memory schnorrSignatureSet
) public {
require(
SchnorrSignatureVerify(
schnorrSignatureSet.message,
schnorrSignatureSet.publicKey,
schnorrSignatureSet.ecR,
schnorrSignatureSet.s
),
"invalid signature"
);
require(!_spents[msg.sender][recipientCommitmentOldId], "commitment already used");
PointEC memory ecH = _genPointEC(abi.encodePacked(gx, gy));
PointEC memory userCommitment = _commitmentById[msg.sender][recipientCommitmentOldId]
.commitment;
(uint256 x, uint256 y) = ePedersenCommitmentPK(
amount,
schnorrSignatureSet.publicKey.x,
schnorrSignatureSet.publicKey.y,
ecH.x,
ecH.y
);
require(x == userCommitment.x && y == userCommitment.y, "this amount cannot be withdrawn");
(uint256 xftAmount, ) = priceConsumer.exchangeAssets(
uint8(_commitmentById[msg.sender][recipientCommitmentOldId].asset),
uint8(Assets.XFT),
amount
);
xftTokenAddress.mint(msg.sender, xftAmount);
_spents[msg.sender][recipientCommitmentOldId] = true;
emit Withdrawn(msg.sender, amount, recipientCommitmentOldId, userCommitment);
}
/**
* @dev Group commitments with same assets, create new groupped commitment.
* @param _commIds Commitment ids that must be closed.
* @param _asset Commitmen asset.
* @param _ecNewCommitment New commitment.
* @param _pkSum Elliptic curve point for verification new commitment.
Subtracting grouped commitment and new must be equal to this point
(_pkSum = subtraction sum of public keys used for already existen commitments and public key used for new commitment)
*/
function groupCommitment(
uint256[] memory _commIds,
Assets _asset,
PointEC memory _ecNewCommitment,
PointEC memory _pkSum
) public {
PointEC memory grouped = _commitmentById[msg.sender][_commIds[0]].commitment;
for (uint256 i = 1; i < _commIds.length; i++) {
require(
_commitmentById[msg.sender][_commIds[i - 1]].asset ==
_commitmentById[msg.sender][_commIds[i]].asset,
"Commitments with different assets"
);
(grouped.x, grouped.y) = eAdd(
grouped.x,
grouped.y,
_commitmentById[msg.sender][_commIds[i]].commitment.x,
_commitmentById[msg.sender][_commIds[i]].commitment.y
);
}
require(_CommitmentVerify(grouped, _ecNewCommitment, _pkSum), "invalid commitment");
for (uint256 i = 0; i < _commIds.length; i++) {
_spents[msg.sender][_commIds[i]] = true;
}
uint256 id = _CommitmentNewAdd(msg.sender, _ecNewCommitment, _asset);
emit Grouped(msg.sender, id, _ecNewCommitment);
}
/**
* @dev Save commitment to user with id.
* @param _newOwner Address of user.
* @param _commitment Commitment.
* @param _asset Commitmen asset.
*/
function _CommitmentNewAdd(
address _newOwner,
PointEC memory _commitment,
Assets _asset
) internal returns (uint256) {
uint256 _id = _idsByAddress[_newOwner].length + 1;
_commitmentById[_newOwner][_id].commitment = _commitment;
_commitmentById[_newOwner][_id].asset = _asset;
_idsByAddress[_newOwner].push(_id);
_spents[_newOwner][_id] = false;
return _id;
}
/**
* @dev Function for verify 2 commitments. Subtracting two points must be equal to the third point.
* @param _ecCommInput First point.
* @param _ecCommOutput Second point.
* @param _ecCommValid Point of equality with the result of subtraction 2 points.
*/
function _CommitmentVerify(
PointEC memory _ecCommInput,
PointEC memory _ecCommOutput,
PointEC memory _ecCommValid
) internal pure returns (bool) {
PointEC memory _ecP;
(_ecP.x, _ecP.y) = eSub(_ecCommInput.x, _ecCommInput.y, _ecCommOutput.x, _ecCommOutput.y);
return _equalPointEC(_ecP, _ecCommValid);
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "./EllipticCurveMath.sol";
contract EllipticCurve {
// y^2 = x^3 + a*x + b (mod p) - elliptic curve
// aa, bb, (gx, gy), pp, nn - recommended parameters for elliptic curve secp256k1
uint256 public constant pp =
uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F); // prime number p, constraint for y^2
uint256 public constant nn =
uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141); // prime number n, constraint for x
// gx, gy - base point G coordinates
uint256 public constant gx =
uint256(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798);
uint256 public constant gy =
uint256(0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8);
uint256 public constant aa =
uint256(0x0000000000000000000000000000000000000000000000000000000000000000);
uint256 public constant bb =
uint256(0x0000000000000000000000000000000000000000000000000000000000000007);
/**
* @dev eAdd returns the sum of (x1,y1) and (x2,y2) elliptic curve points coordinates.
* @param _x1 X coordinate of first point.
* @param _y1 Y coordinate of first point.
* @param _x2 X coordinate of second point.
* @param _y2 Y coordinate of second point.
* @return _x3 _y3 point coordinates.
*/
function eAdd(
uint256 _x1,
uint256 _y1,
uint256 _x2,
uint256 _y2
) public pure returns (uint256 _x3, uint256 _y3) {
(_x3, _y3) = EllipticCurveMath._ecAdd(_x1, _y1, _x2, _y2, 0, pp);
}
/**
* @dev eSub substract two points (x1, y1) and (x2, y2).
* @param _x1 X coordinate of first point.
* @param _y1 Y coordinate of first point.
* @param _x2 X coordinate of second point.
* @param _y2 Y coordinate of second point.
* @return _x3 _y3 point coordinates.
*/
function eSub(
uint256 _x1,
uint256 _y1,
uint256 _x2,
uint256 _y2
) public pure returns (uint256 _x3, uint256 _y3) {
(_x3, _y3) = EllipticCurveMath._ecSub(_x1, _y1, _x2, _y2, 0, pp);
}
/**
* @dev Multiplies point by scalar and returns the resulting point.
* @param _z scalar.
* @param _x1 X coordinate of point.
* @param _y1 Y coordinate of point.
* @return _x2 _y2 point coordinates.
*/
function eMul(
uint256 _z,
uint256 _x1,
uint256 _y1
) public pure returns (uint256 _x2, uint256 _y2) {
(_x2, _y2) = EllipticCurveMath._ecMul(_z, _x1, _y1, 0, pp);
}
/**
* @dev Returns EC point coordinate y with known x
* @param _prefix parity byte (0x02 even, 0x03 odd).
* @param _x coordinate x.
* @return _y coordinate y.
*/
function eDeriveY(uint8 _prefix, uint256 _x) public pure returns (uint256 _y) {
_y = EllipticCurveMath._deriveY(_prefix, _x, aa, bb, pp);
}
/**
* @dev Check is point on curve and return true if (x,y) in the curve, else - false
* @param _x X coordinate of point.
* @param _y Y coordinate of point.
* @return _is result of check.
*/
function eIsOnCurve(uint256 _x, uint256 _y) public pure returns (bool _is) {
_is = EllipticCurveMath._isOnCurve(_x, _y, aa, bb, pp);
}
/**
* @dev Modular euclidean inverse of a number (mod p).
* @param _x value.
* @param _pp mod.
* @return _g inversed value.
*/
function invMod(uint256 _x, uint256 _pp) public pure returns (uint256 _g) {
_g = EllipticCurveMath._invMod(_x, _pp);
}
// Modular exponentiation, returns '_base' raised to the power of '_exp' modulo '_pp'
function expMod(
uint256 _base,
uint256 _exp,
uint256 _pp
) public pure returns (uint256 _r) {
_r = EllipticCurveMath._expMod(_base, _exp, _pp);
}
/**
* @dev Generates the point of an elliptic curve inverted to (_x1, _y1)
* @param _x1 Secret value x.
* @param _y1 Blinding factor to x - r.
* @return _x2 _y2 point coordinates.
*/
function eInv(uint256 _x1, uint256 _y1) public pure returns (uint256 _x2, uint256 _y2) {
(_x2, _y2) = EllipticCurveMath._ecInv(_x1, _y1, pp);
}
/**
* @dev Generates Pederson Commitment with no fixed points x*G + r*H
* @param _x Secret value x.
* @param _r Blinding factor to x - r.
* @param _gx X coordinate of point G.
* @param _gy Y coordinate of point G.
* @param _hx X coordinate of point H.
* @param _hy Y coordinate of point H.
* @return _x3 _y3 point coordinates.
*/
function ePedersenCommitment(
uint256 _x,
uint256 _r,
uint256 _gx,
uint256 _gy,
uint256 _hx,
uint256 _hy
) public pure returns (uint256 _x3, uint256 _y3) {
// x*G
(uint256 _x1, uint256 _y1) = eMul(_x, _gx, _gy);
// r*H
(uint256 _x2, uint256 _y2) = eMul(_r, _hx, _hy);
// x*G+r*H
(_x3, _y3) = eAdd(_x1, _y1, _x2, _y2);
}
/**
* @dev Generates Pederson Commitment with no fixed points x*G + r*H, when x*G is already calculated.
* @param _r Blinding factor to x - r.
* @param _pkx X coordinate of calculated left part(x*G).
* @param _pky Y coordinate of calculated left part(x*G).
* @param _hx X coordinate of point H.
* @param _hy Y coordinate of point H.
* @return _x3 _y3 point coordinates.
*/
function ePedersenCommitmentPK(
uint256 _r,
uint256 _pkx,
uint256 _pky,
uint256 _hx,
uint256 _hy
) public pure returns (uint256 _x3, uint256 _y3) {
// _r*H
(uint256 _x2, uint256 _y2) = eMul(_r, _hx, _hy);
// _pkx - (x*H)
// _pkx + _r*H
(_x3, _y3) = eAdd(_pkx, _pky, _x2, _y2);
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
//Elliptic Curve Library
//Library providing arithmetic operations over elliptic curves.
//This library does not check whether the inserted points belong to the curve
//`isOnCurve` function should be used by the library user to check the aforementioned statement.
//@author Witnet Foundation
library EllipticCurveMath {
// Pre-computed constant for 2 ** 255
uint256 private constant _U255_MAX_PLUS_1 =
57896044618658097711785492504343953926634992332820282019728792003956564819968;
// Modular euclidean inverse of a number (mod p).
// q such that x*q = 1 (mod _pp)
function _invMod(uint256 _x, uint256 _pp) internal pure returns (uint256) {
require(_x != 0 && _x != _pp && _pp != 0, "Invalid number");
uint256 q = 0;
uint256 newT = 1;
uint256 r = _pp;
uint256 t;
while (_x != 0) {
t = r / _x;
(q, newT) = (newT, addmod(q, (_pp - mulmod(t, newT, _pp)), _pp));
(r, _x) = (_x, r - t * _x);
}
return q;
}
/// Modular exponentiation, b^e % _pp.
/// Source: https://github.com/androlo/standard-contracts/blob/master/contracts/src/crypto/ECCMath.sol
/// r such that r = b**e (mod _pp)
function _expMod(
uint256 _base,
uint256 _exp,
uint256 _pp
) internal pure returns (uint256) {
require(_pp != 0, "Modulus is zero");
if (_base == 0) return 0;
if (_exp == 0) return 1;
uint256 r = 1;
uint256 bit = _U255_MAX_PLUS_1;
assembly {
for {
} gt(bit, 0) {
} {
r := mulmod(mulmod(r, r, _pp), exp(_base, iszero(iszero(and(_exp, bit)))), _pp)
r := mulmod(
mulmod(r, r, _pp),
exp(_base, iszero(iszero(and(_exp, div(bit, 2))))),
_pp
)
r := mulmod(
mulmod(r, r, _pp),
exp(_base, iszero(iszero(and(_exp, div(bit, 4))))),
_pp
)
r := mulmod(
mulmod(r, r, _pp),
exp(_base, iszero(iszero(and(_exp, div(bit, 8))))),
_pp
)
bit := div(bit, 16)
}
}
return r;
}
// Converts a point (x, y, z) expressed in Jacobian coordinates to affine coordinates (x', y', 1).
// (x', y') affine coordinates
function _toAffine(
uint256 _x,
uint256 _y,
uint256 _z,
uint256 _pp
) internal pure returns (uint256, uint256) {
uint256 zInv = _invMod(_z, _pp);
uint256 zInv2 = mulmod(zInv, zInv, _pp);
uint256 x2 = mulmod(_x, zInv2, _pp);
uint256 y2 = mulmod(_y, mulmod(zInv, zInv2, _pp), _pp);
return (x2, y2);
}
// Derives the y coordinate from a compressed-format point x [[SEC-1]](https://www.secg.org/SEC1-Ver-1.0.pdf).
// _prefix parity byte (0x02 even, 0x03 odd)
// return y coordinate y
function _deriveY(
uint8 _prefix,
uint256 _x,
uint256 _aa,
uint256 _bb,
uint256 _pp
) internal pure returns (uint256) {
require(_prefix == 0x02 || _prefix == 0x03, "Invalid compressed EC point prefix");
// x^3 + ax + b
uint256 y2 = addmod(
mulmod(_x, mulmod(_x, _x, _pp), _pp),
addmod(mulmod(_x, _aa, _pp), _bb, _pp),
_pp
);
y2 = _expMod(y2, (_pp + 1) / 4, _pp);
uint256 y = (y2 + _prefix) % 2 == 0 ? y2 : _pp - y2;
return y;
}
// Check whether point (x,y) is on curve defined by a, b, and _pp.
//return true if x,y in the curve, false else
function _isOnCurve(
uint256 _x,
uint256 _y,
uint256 _aa,
uint256 _bb,
uint256 _pp
) internal pure returns (bool) {
if (0 == _x || _x >= _pp || 0 == _y || _y >= _pp) {
return false;
}
// y^2
uint256 lhs = mulmod(_y, _y, _pp);
// x^3
uint256 rhs = mulmod(mulmod(_x, _x, _pp), _x, _pp);
if (_aa != 0) {
// x^3 + a*x
rhs = addmod(rhs, mulmod(_x, _aa, _pp), _pp);
}
if (_bb != 0) {
// x^3 + a*x + b
rhs = addmod(rhs, _bb, _pp);
}
return lhs == rhs;
}
//Calculate inverse (x, -y) of point (x, y).
//return (x, -y)
function _ecInv(
uint256 _x,
uint256 _y,
uint256 _pp
) internal pure returns (uint256, uint256) {
return (_x, (_pp - _y) % _pp);
}
// Add two points (x1, y1) and (x2, y2) in affine coordinates.
// return (qx, qy) = P1+P2 in affine coordinates
function _ecAdd(
uint256 _x1,
uint256 _y1,
uint256 _x2,
uint256 _y2,
uint256 _aa,
uint256 _pp
) internal pure returns (uint256, uint256) {
uint256 x = 0;
uint256 y = 0;
uint256 z = 0;
if (_x1 == _x2) {
// y1 = -y2 mod p
if (addmod(_y1, _y2, _pp) == 0) {
return (0, 0);
} else {
// P1 = P2
(x, y, z) = _jacDouble(_x1, _y1, 1, _aa, _pp);
}
} else {
(x, y, z) = _jacAdd(_x1, _y1, 1, _x2, _y2, 1, _pp);
}
// Get back to affine
return _toAffine(x, y, z, _pp);
}
// Substract two points (x1, y1) and (x2, y2) in affine coordinates.
// return (qx, qy) = P1-P2 in affine coordinates
function _ecSub(
uint256 _x1,
uint256 _y1,
uint256 _x2,
uint256 _y2,
uint256 _aa,
uint256 _pp
) internal pure returns (uint256, uint256) {
// invert square
(uint256 x, uint256 y) = _ecInv(_x2, _y2, _pp);
// P1-square
return _ecAdd(_x1, _y1, x, y, _aa, _pp);
}
// Multiply point (x1, y1, z1) times d in affine coordinates.
// return (qx, qy) = d*P in affine coordinates
function _ecMul(
uint256 _k,
uint256 _x,
uint256 _y,
uint256 _aa,
uint256 _pp
) internal pure returns (uint256, uint256) {
// Jacobian multiplication
(uint256 x1, uint256 y1, uint256 z1) = _jacMul(_k, _x, _y, 1, _aa, _pp);
// Get back to affine
return _toAffine(x1, y1, z1, _pp);
}
// Adds two points (x1, y1, z1) and (x2 y2, z2).
// return (qx, qy, qz) P1+square in Jacobian
function _jacAdd(
uint256 _x1,
uint256 _y1,
uint256 _z1,
uint256 _x2,
uint256 _y2,
uint256 _z2,
uint256 _pp
)
internal
pure
returns (
uint256,
uint256,
uint256
)
{
if (_x1 == 0 && _y1 == 0) return (_x2, _y2, _z2);
if (_x2 == 0 && _y2 == 0) return (_x1, _y1, _z1);
// We follow the equations described in
// https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5
uint256[4] memory zs; // z1^2, z1^3, z2^2, z2^3
zs[0] = mulmod(_z1, _z1, _pp);
zs[1] = mulmod(_z1, zs[0], _pp);
zs[2] = mulmod(_z2, _z2, _pp);
zs[3] = mulmod(_z2, zs[2], _pp);
// u1, s1, u2, s2
zs = [
mulmod(_x1, zs[2], _pp),
mulmod(_y1, zs[3], _pp),
mulmod(_x2, zs[0], _pp),
mulmod(_y2, zs[1], _pp)
];
// In case of zs[0] == zs[2] && zs[1] == zs[3], double function should be used
require(zs[0] != zs[2] || zs[1] != zs[3], "Use jacDouble function instead");
uint256[4] memory hr;
//h
hr[0] = addmod(zs[2], _pp - zs[0], _pp);
//r
hr[1] = addmod(zs[3], _pp - zs[1], _pp);
//h^2
hr[2] = mulmod(hr[0], hr[0], _pp);
// h^3
hr[3] = mulmod(hr[2], hr[0], _pp);
// qx = -h^3 -2u1h^2+r^2
uint256 qx = addmod(mulmod(hr[1], hr[1], _pp), _pp - hr[3], _pp);
qx = addmod(qx, _pp - mulmod(2, mulmod(zs[0], hr[2], _pp), _pp), _pp);
// qy = -s1*z1*h^3+r(u1*h^2 -x^3)
uint256 qy = mulmod(hr[1], addmod(mulmod(zs[0], hr[2], _pp), _pp - qx, _pp), _pp);
qy = addmod(qy, _pp - mulmod(zs[1], hr[3], _pp), _pp);
// qz = h*z1*z2
uint256 qz = mulmod(hr[0], mulmod(_z1, _z2, _pp), _pp);
return (qx, qy, qz);
}
// Doubles a points (x, y, z).
// return (qx, qy, qz) 2P in Jacobian
function _jacDouble(
uint256 _x,
uint256 _y,
uint256 _z,
uint256 _aa,
uint256 _pp
)
internal
pure
returns (
uint256,
uint256,
uint256
)
{
if (_z == 0) return (_x, _y, _z);
// We follow the equations described in
// https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5
// Note: there is a bug in the paper regarding the m parameter, M=3*(x1^2)+a*(z1^4)
// x, y, z at this point represent the squares of _x, _y, _z
uint256 x = mulmod(_x, _x, _pp); //x1^2
uint256 y = mulmod(_y, _y, _pp); //y1^2
uint256 z = mulmod(_z, _z, _pp); //z1^2
// s
uint256 s = mulmod(4, mulmod(_x, y, _pp), _pp);
// m
uint256 m = addmod(mulmod(3, x, _pp), mulmod(_aa, mulmod(z, z, _pp), _pp), _pp);
// x, y, z at this point will be reassigned and rather represent qx, qy, qz from the paper
// This allows to reduce the gas cost and stack footprint of the algorithm
// qx
x = addmod(mulmod(m, m, _pp), _pp - addmod(s, s, _pp), _pp);
// qy = -8*y1^4 + M(S-T)
y = addmod(
mulmod(m, addmod(s, _pp - x, _pp), _pp),
_pp - mulmod(8, mulmod(y, y, _pp), _pp),
_pp
);
// qz = 2*y1*z1
z = mulmod(2, mulmod(_y, _z, _pp), _pp);
return (x, y, z);
}
// Multiply point (x, y, z) times d.
// return (qx, qy, qz) d*P1 in Jacobian
function _jacMul(
uint256 _d,
uint256 _x,
uint256 _y,
uint256 _z,
uint256 _aa,
uint256 _pp
)
internal
pure
returns (
uint256,
uint256,
uint256
)
{
// Early return in case that `_d == 0`
if (_d == 0) {
return (_x, _y, _z);
}
uint256 remaining = _d;
uint256 qx = 0;
uint256 qy = 0;
uint256 qz = 1;
// Double and add algorithm
while (remaining != 0) {
if ((remaining & 1) != 0) {
(qx, qy, qz) = _jacAdd(qx, qy, qz, _x, _y, _z, _pp);
}
remaining = remaining / 2;
(_x, _y, _z) = _jacDouble(_x, _y, _z, _aa, _pp);
}
return (qx, qy, qz);
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "./interfaces/IPriceConsumer.sol";
contract PriceConsumer is IPriceConsumer {
/**
* Network: Rinkeby
* Aggregators: ETH/USD, BTC/USD, XAU/USD, XFT/USD
*/
enum Assets {
XFT,
USD,
BTC,
ETH,
XAU
}
uint8 internal constant _decimalmax = 18;
constructor() {}
/**
* @dev Returns required input amount of the asset given an output amount of other asset.
* @param exchAggr aggregator of input asset.
* @param quoteAggr aggregator of output asset.
* @param exchAmount output amount.
* @return input amount and decimals.
*/
function exchangeAssets(
uint8 exchAggr,
uint8 quoteAggr,
uint256 exchAmount
) external view override returns (uint256, uint8) {
require(exchAggr != quoteAggr, "Aggregator names are the same");
(uint256 _quotePrice, uint8 _quoteDecimal) = getDerivedPrice(exchAggr, quoteAggr);
return (uint256(exchAmount * _quotePrice) / (uint256(10**_quoteDecimal)), _quoteDecimal);
}
/**
* @dev Returns output amount of the asset given other asset.
* @param baseAggr input asset agregator.
* @param quoteAggr output asset agregator.
* @return amount and decimals.
*/
function getDerivedPrice(uint8 baseAggr, uint8 quoteAggr)
public
view
returns (uint256, uint8)
{
(int256 _basePrice, uint8 _baseDecimals) = getLatestPrice(baseAggr);
(int256 _quotePrice, uint8 _quoteDecimals) = getLatestPrice(quoteAggr);
(_basePrice, _baseDecimals) = _scalePrice(_basePrice, _baseDecimals, _decimalmax);
(_quotePrice, _quoteDecimals) = _scalePrice(_quotePrice, _quoteDecimals, _decimalmax);
return (
uint256((_basePrice * (int256(10**uint256(_baseDecimals)))) / _quotePrice),
_quoteDecimals
);
}
/**
* @dev Returns the latest price.
* @param aggregator Token name by number in Assets enum.
* @return price and decimals
*/
function getLatestPrice(uint8 aggregator) public view returns (int256, uint8) {
if (aggregator == uint8(Assets.USD)) {
return (int256(10**8), 8);
}
address _addrAggr = _getAddrAggregator(aggregator);
require(_addrAggr != address(0), "Adress aggregator cannot be zero.");
(, int256 _price, , , ) = AggregatorV3Interface(_addrAggr).latestRoundData();
uint8 _decimals = AggregatorV3Interface(_addrAggr).decimals();
return (_price, _decimals);
}
/**
* @dev Returns the aggregator address.
* @param _aggregator Token name by number in Assets enum.
* @return address.
*/
function _getAddrAggregator(uint8 _aggregator) internal pure returns (address) {
address _addrAggregator;
if (_aggregator == uint8(Assets.BTC))
_addrAggregator = 0xECe365B379E1dD183B20fc5f022230C044d51404;
if (_aggregator == uint8(Assets.ETH))
_addrAggregator = 0x8A753747A1Fa494EC906cE90E9f37563A8AF630e;
if (_aggregator == uint8(Assets.XAU))
_addrAggregator = 0x81570059A0cb83888f1459Ec66Aad1Ac16730243;
if (_aggregator == uint8(Assets.XFT))
_addrAggregator = 0xab4a352ac35dFE83221220D967Db41ee61A0DeFa;
return _addrAggregator;
}
/**
* @dev Convert the price to the set decimals.
* @param _price Token name by number in Assets enum.
* @param _priceDecimals Token name by number in Assets enum.
* @param _decimals Token name by number in Assets enum.
* @return price and decimals.
*/
function _scalePrice(
int256 _price,
uint8 _priceDecimals,
uint8 _decimals
) internal pure returns (int256, uint8) {
if (_priceDecimals < _decimals) {
return (_price * int256(10**uint256(_decimals - _priceDecimals)), _decimals);
} else if (_priceDecimals > _decimals) {
return (_price / int256(10**uint256(_priceDecimals - _decimals)), _priceDecimals);
}
return (_price, _priceDecimals);
}
/**
* @dev Function for check aggregators equality.
* @param _aggr Token name by number in Assets enum.
* @param _name Token name by number in Assets enum.
* @return result of the equality check.
*/
function _isEqualAggr(string memory _aggr, string memory _name) internal pure returns (bool) {
bool _isEq = bytes(_aggr).length == bytes(_name).length;
for (uint8 i = 0; i < bytes(_aggr).length; i++) {
_isEq = _isEq && (bytes(_aggr)[i] == bytes(_name)[i]);
}
return _isEq;
}
}
pragma solidity =0.8.4;
import "../EC/EllipticCurve.sol";
contract RangeProofMath is EllipticCurve {
// elliptic curve point structure
struct PointEC {
uint256 x;
uint256 y;
}
// set of data to verify the range proof, where
// n is the number of bits in the secret
// m - the number of participants to generate an aggregate range proof
// k is the number of iterations for the compression operation
struct SlotCount {
uint256 n;
uint256 m; //count Vj
uint256 k; //count L and R
}
// chellenges for range proof verification
struct SlotChallenge {
uint256 y;
uint256 z;
uint256 x;
uint256 w;
uint256 delta;
}
// Range Proof structure
struct SlotRangeProof {
PointEC[] arrVj;
PointEC ecA;
PointEC ecS;
PointEC ecT1;
PointEC ecT2;
uint256 utx;
uint256 uttx;
uint256 uee;
PointEC[] arrLk;
PointEC[] arrRk;
uint256 ua;
uint256 ub;
}
// Point to hash function
function _hashPPToChallange(PointEC memory _pEC_1, PointEC memory _pEC_2)
internal
pure
returns (uint256)
{
return uint256(sha256(abi.encode(_pEC_1.x, _pEC_1.y, _pEC_2.x, _pEC_2.y)));
}
// function for calculating '_negM' opposite to '_v' modulo 'nn', where
// _negM + _v = 0 (mod nn)
function _negMod(uint256 _v) internal pure returns (uint256 _negM) {
_negM = mulmod(1, _v, nn);
_negM = nn - _negM;
}
// function for calculating vector arrInvYn inverse to _arrMatr modulo _mod, where
// [_arrMatr] = [arrInvYn] ^ (- 1) (mod _mod)
function _invMatrMod(uint256[] memory _arrMatr, uint256 _mod)
internal
pure
returns (uint256[] memory _arrInvMatr)
{
_arrInvMatr = new uint256[](_arrMatr.length);
for (uint8 i = 0; i < _arrMatr.length; i++) {
_arrInvMatr[i] = invMod(_arrMatr[i], _mod);
}
}
// '_paramSHA' - input to start generation
// function for generating a point on an elliptic curve
function _genPointEC(bytes memory _paramSHA) internal pure returns (PointEC memory _pEC) {
uint256 _x;
uint256 _y;
uint8 _i;
while (_i < 256) {
_x = addmod(uint256(0), uint256(sha256(abi.encodePacked(_i, _paramSHA))), pp);
_y = eDeriveY(2, _x);
if (eIsOnCurve(_x, _y) == true) {
_pEC.x = _x;
_pEC.y = _y;
return _pEC;
}
_i++;
}
}
// '_paramSHA' - input to start generation
// '_n' - vector size
// function for generating a vector of elliptic curve points
function _genMatrixECPoints(bytes memory _paramSHA, uint256 _n)
internal
pure
returns (PointEC[] memory _matrixECPoints)
{
_matrixECPoints = new PointEC[](_n);
for (uint8 i = 0; i < _n; i++) {
_matrixECPoints[i] = _genPointEC(abi.encodePacked(_paramSHA, i));
if (_matrixECPoints[i].y < uint256(pp / 2)) {
_matrixECPoints[i].y = pp - _matrixECPoints[i].y;
}
}
}
// function for checking the equality of two points of an elliptic curve
function _equalPointEC(PointEC memory _pEC1, PointEC memory _pEC2)
internal
pure
returns (bool _isEq)
{
_isEq = (_pEC1.x == _pEC2.x) && (_pEC1.y == _pEC2.y);
}
// function for calculation vector u, parameter for 'inner product' verification
function _calc_matrix_u(
uint256 _k,
PointEC[] memory _arrLk,
PointEC[] memory _arrRk
) internal pure returns (uint256[] memory _arrUk) {
_arrUk = new uint256[](_k);
for (uint8 i = 0; i < _k; i++) {
_arrUk[i] = mulmod(1, _hashPPToChallange(_arrLk[i], _arrRk[i]), nn);
}
}
// function for calculation delta, parameter for 'polinom tx' verification
function _calc_delta(SlotCount memory _count, SlotChallenge memory _challenge)
internal
pure
returns (uint256 _delta)
{
uint256 _n = _count.n;
uint256 _m = _count.m;
uint256 _y = _challenge.y;
uint256 _z = _challenge.z;
uint256 _v1 = 1; //y^n
uint256 _v2 = 1; //2^n
uint256 _spm1 = 1; // <1, y^n>
uint256 _spm2 = 1; // <1, 2^n>
uint256 _zz = mulmod(_z, _z, nn); //z^2 mod k
// _zz = addmod(_negMod(_zz), _z, nn); // z-z^2
// (z-z^2) * <1, y ^ n*m> === (z-z^2)* m * <1, y^n>
for (uint8 i = 1; i < _n; i++) {
_v1 = mulmod(_v1, _y, nn);
_spm1 = addmod(_spm1, _v1, nn); // <1, y^n>
_v2 = mulmod(_v2, 2, nn);
_spm2 = addmod(_spm2, _v2, nn); // <1, 2^n>
}
_delta = mulmod(mulmod(_spm1, _m, nn), addmod(_negMod(_zz), _z, nn), nn); // (z-z^2)* m * <1, y^n>
// -z^3*summ(z^j)*<1, 2^nm> == -summ(z^j) * z^3 * m * <1, 2^n>
_spm1 = 1;
for (uint256 j = 1; j < _m; j++) {
_v1 = mulmod(_v1, _z, nn); //z^j
_spm1 = addmod(_spm1, _v1, nn); // summ(z^j)
}
_spm1 = mulmod(mulmod(_zz, _z, nn), _spm1, nn);
_spm1 = mulmod(_spm1, mulmod(_spm2, _m, nn), nn);
_delta = addmod(_delta, _negMod(_spm1), nn);
}
// function for calculation challange y
function _calcChallY(PointEC memory _ecA, PointEC memory _ecS)
internal
pure
returns (uint256 _chall)
{
require(eIsOnCurve(_ecA.x, _ecA.y), "Argument '_ecA' is not ec point");
require(eIsOnCurve(_ecS.x, _ecS.y), "Argument '_ecS' is not ec point");
_chall = addmod(0, _hashPPToChallange(_ecA, _ecS), nn);
}
// function for calculation challange z
function _calcChallZ(
PointEC memory _ecA,
PointEC memory _ecS,
uint256 _y
) internal pure returns (uint256 _chall) {
_chall = addmod(0, uint256(sha256(abi.encode(_ecA.x, _ecA.y, _ecS.x, _ecS.y, _y))), nn);
}
// function for calculation challange x
function _calcChallX(PointEC memory _ecT1, PointEC memory _ecT2)
internal
pure
returns (uint256 _chall)
{
require(eIsOnCurve(_ecT1.x, _ecT1.y), "Argument '_ecT1' is not ec point");
require(eIsOnCurve(_ecT2.x, _ecT2.y), "Argument '_ecT2' is not ec point");
_chall = addmod(0, _hashPPToChallange(_ecT1, _ecT2), nn);
}
// function for calculation challange w
function _calcChallW(
uint256 _tx,
uint256 _ttx,
uint256 _ee
) internal pure returns (uint256 _chall) {
_chall = addmod(0, uint256(sha256(abi.encode(_tx, _ttx, _ee))), nn);
}
// function for calculation number of parameters for the SlotCount structure
function _calc_counters(
PointEC[] memory _Vj,
PointEC[] memory _Lk,
PointEC[] memory _Rk
) internal pure returns (SlotCount memory _count) {
//m- number of participants
_count.m = _Vj.length;
require(_count.m > 0, "Array Vj is empty");
_count.k = _Lk.length;
require(_count.k > 0, "Arrays Lk and Rk with an error");
require(_count.k == _Rk.length, "Rk and Lk have different sizes");
//n- length 'v' in bits or k = log2(n) => n = 2^k
_count.n = 2**_count.k;
}
// function for calculation vector with size _n from the powers of _v modulo _mod,
// where _v ^ i (mod _mod), i = {0, 1, _n-1}
function _gen_matrix_product(
uint8 _n,
uint256 _v,
uint256 _mod
) internal pure returns (uint256[] memory arrProd) {
arrProd = new uint256[](_n);
arrProd[0] = 1;
for (uint8 i = 1; i < _n; i++) {
arrProd[i] = mulmod(arrProd[i - 1], _v, _mod);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "./RP/RangeProofMath.sol";
contract RangeProof is RangeProofMath {
PointEC internal ecB; //point ec B
PointEC internal ecBB; // point ec B'
uint8 internal constant n = 64; // bits amount of secret value
uint8 internal constant k = 6; // number of iterations for compression inner products, the dependence n = 2^k
constructor() {
(ecB.x, ecB.y) = (gx, gy);
ecBB = _genPointEC(abi.encodePacked(ecB.x, ecB.y));
}
/**
* @dev Verify polinom tx verification.
* @param rp range proof elements.
* @return result of verification.
*/
function verifyPolinom(SlotRangeProof memory rp) external view returns (bool) {
PointEC memory _leftPart;
PointEC memory _rightPart;
PointEC memory _pEC;
uint256 _product;
SlotCount memory _count = _calc_counters(rp.arrVj, rp.arrLk, rp.arrRk);
SlotChallenge memory _challenge;
_challenge.y = _calcChallY(rp.ecA, rp.ecS);
_challenge.z = _calcChallZ(rp.ecA, rp.ecS, _challenge.y);
_challenge.x = _calcChallX(rp.ecT1, rp.ecT2);
_challenge.delta = _calc_delta(_count, _challenge);
_product = mulmod(_challenge.z, _challenge.z, nn); // z^2
(_rightPart.x, _rightPart.y) = eMul(_product, rp.arrVj[0].x, rp.arrVj[0].y); //z^2 * V
for (uint8 j = 1; j < _count.m; j++) {
_product = mulmod(_product, _challenge.z, nn);
(_pEC.x, _pEC.y) = eMul(_product, rp.arrVj[j].x, rp.arrVj[j].y); //z^(j+1)*V[j]
(_rightPart.x, _rightPart.y) = eAdd(_rightPart.x, _rightPart.y, _pEC.x, _pEC.y);
}
(_pEC.x, _pEC.y) = eMul(_challenge.delta, ecB.x, ecB.y); // delta*B
(_rightPart.x, _rightPart.y) = eAdd(_rightPart.x, _rightPart.y, _pEC.x, _pEC.y); //... + delta*B
(_pEC.x, _pEC.y) = eMul(_challenge.x, rp.ecT1.x, rp.ecT1.y); //x*T1
(_rightPart.x, _rightPart.y) = eAdd(_rightPart.x, _rightPart.y, _pEC.x, _pEC.y); // ... + x*T1
(_pEC.x, _pEC.y) = eMul(mulmod(_challenge.x, _challenge.x, nn), rp.ecT2.x, rp.ecT2.y); //x^2*T2
(_rightPart.x, _rightPart.y) = eAdd(_rightPart.x, _rightPart.y, _pEC.x, _pEC.y); //... + x^2*T2
(_leftPart.x, _leftPart.y) = ePedersenCommitment(
rp.utx,
rp.uttx,
ecB.x,
ecB.y,
ecBB.x,
ecBB.y
);
return _equalPointEC(_leftPart, _rightPart);
}
/**
* @dev Generate matrix H of elliptic curve points.
* @param mj stringValue.
* @return ecMatrHj H(stringValue)
*/
function genMatrixH(uint8 mj) external view returns (PointEC[] memory ecMatrHj) {
bytes memory _paramSHA = abi.encode(ecBB.x, ecBB.y);
ecMatrHj = _genMatrixECPoints(abi.encodePacked(_paramSHA, mj), n);
}
/**
* @dev Generate matrix G og elliptic curve points.
* @param mj H(Lk, Rk).
* @return ecMatrGj u[j]^b(i,j).
*/
function genMatrixG(uint8 mj) external view returns (PointEC[] memory ecMatrGj) {
// matrix G j
bytes memory _paramSHA = abi.encode(ecB.x, ecB.y);
ecMatrGj = _genMatrixECPoints(abi.encodePacked(_paramSHA, mj), n);
}
/**
* @dev Returns left part of IPP.
* @param rp range proof elements.
* @param ecGk G piint.
* @param ecHHk H point
* @return ecRight EC point, calculated left part of IPP.
*/
function getVerifyInnerProductLeft(
SlotRangeProof memory rp,
PointEC memory ecGk,
PointEC memory ecHHk
) external view returns (PointEC memory ecRight) {
// a*<s, G> + b*<1/s, H> + a*b*Q
PointEC memory _pEC;
(ecRight.x, ecRight.y) = eMul(rp.ua, ecGk.x, ecGk.y); // a*<s, G>
(_pEC.x, _pEC.y) = eMul(rp.ub, ecHHk.x, ecHHk.y); // b*<1/s, H'>
(ecRight.x, ecRight.y) = eAdd(ecRight.x, ecRight.y, _pEC.x, _pEC.y);
//a*b*(tx*B)
// (_pEC.x, _pEC.y) = eMul(_challenge.w, ecB.x, ecB.y);
(_pEC.x, _pEC.y) = eMul(_calcChallW(rp.utx, rp.uttx, rp.uee), ecB.x, ecB.y);
(_pEC.x, _pEC.y) = eMul(rp.ua, _pEC.x, _pEC.y);
(_pEC.x, _pEC.y) = eMul(rp.ub, _pEC.x, _pEC.y);
(ecRight.x, ecRight.y) = eAdd(ecRight.x, ecRight.y, _pEC.x, _pEC.y);
}
/**
* @dev Calculates IPPP0 - parameter for Inner Product Right.
* @param rp range proof elements.
* @param baseP P piint, calculated by getBaseP function.
*/
function getIPPP0(SlotRangeProof memory rp, PointEC memory baseP)
external
view
returns (PointEC memory ippP0)
{
//P - e'*B' + tx*Q
PointEC memory _pEC;
// e'*B'
(_pEC.x, _pEC.y) = eMul(rp.uee, ecBB.x, ecBB.y);
//- e'*B'
(_pEC.x, _pEC.y) = eInv(_pEC.x, _pEC.y);
(ippP0.x, ippP0.y) = eAdd(baseP.x, baseP.y, _pEC.x, _pEC.y);
(_pEC.x, _pEC.y) = eMul(_calcChallW(rp.utx, rp.uttx, rp.uee), ecB.x, ecB.y); // Q = w*B
(_pEC.x, _pEC.y) = eMul(rp.utx, _pEC.x, _pEC.y); // tx*Q
(ippP0.x, ippP0.y) = eAdd(ippP0.x, ippP0.y, _pEC.x, _pEC.y);
}
/**
* @dev Final Range Proof verification.
* @param verPolinom polinom verification result.
* @param verIPP inner product proof verification result.
* @return Result of verification.
*/
function verifyRP(bool verPolinom, bool verIPP) external pure returns (bool) {
return verPolinom && verIPP;
}
/**
* @dev Inner Product Prove verification.
* @param leftVerIPP left part of IPP: a*<s, G> + b*<1/s, H> + a*b*Q.
* @param rightVerIPP right part of IPP: P0 + <uk^2, L> + <uk^(-2), R>
* @return Result of verification.
*/
function verifyIPP(PointEC memory leftVerIPP, PointEC memory rightVerIPP)
external
pure
returns (bool)
{
return _equalPointEC(leftVerIPP, rightVerIPP);
}
/**
* @dev Calculate vector u, parameter for 'inner product prove' verification.
* @param rp range proof elements.
* @return arrUk H(Lk, Rk).
*/
function genMatrUk(SlotRangeProof memory rp) external pure returns (uint256[] memory arrUk) {
//uk = H(Lk, Rk)
arrUk = _calc_matrix_u(k, rp.arrLk, rp.arrRk);
}
/**
* @dev Calculate vector s, parameter for 'inner product prove' verification.
* @param arrUk H(Lk, Rk.
* @return s u[j]^b(i,j).
*/
function genMatrS(uint256[] memory arrUk) external pure returns (uint256[] memory s) {
uint256 _multipl;
uint256 _prodMultipl;
s = new uint256[](n);
for (uint8 i = 0; i < n; i++) {
_prodMultipl = 1;
for (uint8 j = 1; j <= k; j++) {
//calculation matrix u[j]^b(i,j)
if (mulmod(1, i, 2**j) < 2**(j - 1)) {
//u[i]^-1
_multipl = invMod(arrUk[k - j], nn);
} else {
_multipl = arrUk[k - j];
}
_prodMultipl = mulmod(_prodMultipl, _multipl, nn);
}
s[i] = _prodMultipl;
}
}
/**
* @dev Calculate point G.
* @param s points of u[j]^b(i,j) calculation.
* @param arrG array of G points.
* @return ecGk <s, G>.
*/
function genGk(uint256[] memory s, PointEC[] memory arrG)
external
pure
returns (PointEC memory ecGk)
{
PointEC memory _pEC;
for (uint8 i = 0; i < n; i++) {
(_pEC.x, _pEC.y) = eMul(s[i], arrG[i].x, arrG[i].y);
(ecGk.x, ecGk.y) = eAdd(_pEC.x, _pEC.y, ecGk.x, ecGk.y);
}
}
/**
* @dev Calculate point H.
* @param s points of u[j]^b(i,j) calculation.
* @param arrHH array of H points.
* @return ecHHk <1/s, H'>.
*/
function genHHk(uint256[] memory s, PointEC[] memory arrHH)
external
pure
returns (PointEC memory ecHHk)
{
PointEC memory _pEC;
for (uint8 i = 0; i < n; i++) {
(_pEC.x, _pEC.y) = eMul(s[n - i - 1], arrHH[i].x, arrHH[i].y);
(ecHHk.x, ecHHk.y) = eAdd(ecHHk.x, ecHHk.y, _pEC.x, _pEC.y);
}
}
/**
* @dev Calculate vector of 2^n.
* @return arr2n [2^i], i={0, 1, ..., n-1}.
*/
function genMatr2n() external pure returns (uint256[] memory arr2n) {
arr2n = _gen_matrix_product(n, 2, nn);
}
/**
* @dev Calculate vector of y^n.
* @param rp range proof elements.
* @return arr2n [y^i], i={0, 1, ..., n-1}.
*/
function genMatrYn(SlotRangeProof memory rp) external pure returns (uint256[] memory arr2n) {
arr2n = _gen_matrix_product(n, _calcChallY(rp.ecA, rp.ecS), nn);
}
/**
* @dev Calculate inverse vector of y^n.
* @param arrYn array of elements y^n.
* @return arrInvYn [y]^(-1).
*/
function genInvMatrYn(uint256[] memory arrYn)
external
pure
returns (uint256[] memory arrInvYn)
{
arrInvYn = _invMatrMod(arrYn, nn);
}
/**
* @dev Calculate inverse vector of y^n.
* @param arrUk array of elements u - H(Lk, Rk).
* @return arrUk2 inversed y^n vector.
*/
function genMatrUk2(uint256[] memory arrUk) external pure returns (uint256[] memory arrUk2) {
arrUk2 = new uint256[](k);
for (uint8 j = 0; j < k; j++) {
arrUk2[j] = mulmod(arrUk[j], arrUk[j], nn);
}
}
/**
* @dev Calculate inverse vector of arrU2k with mod nn .
* @param arrU2k array of elements u - H(Lk, Rk).
* @return arrInvU2k inversed arrU2k vector.
*/
function genInvMatrUk2(uint256[] memory arrU2k)
external
pure
returns (uint256[] memory arrInvU2k)
{
arrInvU2k = _invMatrMod(arrU2k, nn);
}
/**
* @dev Calculate vector H', parameter for IPP verification.
* @param arrH array H points.
* @param arrInvYn inversed y^n.
* @return _arrHH [y^(-n)] * [H].
*/
function genMatrHprime(PointEC[] memory arrH, uint256[] memory arrInvYn)
external
pure
returns (PointEC[] memory _arrHH)
{
_arrHH = new PointEC[](arrH.length);
for (uint8 i = 0; i < arrH.length; i++) {
(_arrHH[i].x, _arrHH[i].y) = eMul(arrInvYn[i], arrH[i].x, arrH[i].y); // y^(-n) * H
}
}
/**
* @dev Calculates point P, parameter for IPP verification.
* @param rp range proof elements.
* @param ecMatrG array of G points.
* @param ecMatrHH array of H points.
* @param arr2n array of 2^n elements.
* @param arrYn array of y^n elements.
* @return baseP P = A + x*S - z*<1, G> + <z*y^n + z^2*2^n, H'>.
*/
function getBaseP(
SlotRangeProof memory rp,
PointEC[] memory ecMatrG,
PointEC[] memory ecMatrHH,
uint256[] memory arr2n,
uint256[] memory arrYn
) external pure returns (PointEC memory baseP) {
// P = A + x*S - z*<1, G> + <z*y^n + z^2*2^n, H'>
SlotChallenge memory _challenge;
_challenge.y = _calcChallY(rp.ecA, rp.ecS);
_challenge.z = _calcChallZ(rp.ecA, rp.ecS, _challenge.y);
_challenge.x = _calcChallX(rp.ecT1, rp.ecT2);
uint256 _mul;
uint256 _z2 = mulmod(_challenge.z, _challenge.z, nn); //z^2
PointEC memory _pEC;
// P = A + x*S - z*<1, G> + <z*y^n + z^2*2^n, H'>
// <z*y^n + z^2*2^n, H'>
for (uint8 i = 0; i < ecMatrHH.length; i++) {
_mul = addmod(mulmod(_challenge.z, arrYn[i], nn), mulmod(_z2, arr2n[i], nn), nn); // z*y^n + z^2*2^n
(_pEC.x, _pEC.y) = eMul(_mul, ecMatrHH[i].x, ecMatrHH[i].y); // (z*y^n + z^2*2^n) * H'
(baseP.x, baseP.y) = eAdd(baseP.x, baseP.y, _pEC.x, _pEC.y);
}
(_pEC.x, _pEC.y) = eMul(_challenge.x, rp.ecS.x, rp.ecS.y); //x*S
(_pEC.x, _pEC.y) = eAdd(rp.ecA.x, rp.ecA.y, _pEC.x, _pEC.y); // A + x*S
(baseP.x, baseP.y) = eAdd(_pEC.x, _pEC.y, baseP.x, baseP.y); //A + x*S + <z*y^n + z^2*2^n, H'>
// - z*<1, G>
_pEC = ecMatrG[0];
for (uint8 i = 1; i < ecMatrG.length; i++) {
(_pEC.x, _pEC.y) = eAdd(_pEC.x, _pEC.y, ecMatrG[i].x, ecMatrG[i].y);
}
(_pEC.x, _pEC.y) = eMul(_challenge.z, _pEC.x, _pEC.y);
(_pEC.x, _pEC.y) = eInv(_pEC.x, _pEC.y);
(baseP.x, baseP.y) = eAdd(baseP.x, baseP.y, _pEC.x, _pEC.y); //...+ -z*<1,G>
}
/**
* @dev Calculates point P, parameter for IPP verification.
* @param rp range proof elements.
* @param ecIPPP0 EC point IPPP0.
* @param arrUk2 array of arrU2k.
* @param arrInvUk2 array of inversed arrU2k elements.
* @return x y point coordinates.
*/
function getVerifyInnerProductRight(
SlotRangeProof memory rp,
PointEC memory ecIPPP0,
uint256[] memory arrUk2,
uint256[] memory arrInvUk2
) external pure returns (uint256 x, uint256 y) {
//P0 + <uk^2, L> + <uk^(-2), R>
PointEC memory _ecUL;
PointEC memory _ecUR;
PointEC memory _pEC;
uint8 j;
//<uk^2, L>
for (j = 0; j < rp.arrLk.length; j++) {
(_pEC.x, _pEC.y) = eMul(arrUk2[j], rp.arrLk[j].x, rp.arrLk[j].y);
(_ecUL.x, _ecUL.y) = eAdd(_ecUL.x, _ecUL.y, _pEC.x, _pEC.y);
}
//<uk^(-2), R>
for (j = 0; j < rp.arrRk.length; j++) {
(_pEC.x, _pEC.y) = eMul(arrInvUk2[j], rp.arrRk[j].x, rp.arrRk[j].y);
(_ecUR.x, _ecUR.y) = eAdd(_ecUR.x, _ecUR.y, _pEC.x, _pEC.y);
}
(_pEC.x, _pEC.y) = eAdd(ecIPPP0.x, ecIPPP0.y, _ecUL.x, _ecUL.y);
(_pEC.x, _pEC.y) = eAdd(_pEC.x, _pEC.y, _ecUR.x, _ecUR.y);
return (_pEC.x, _pEC.y);
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "./RP/RangeProofMath.sol";
contract SchnorrSignature is RangeProofMath {
struct SlotSchnorrSignature {
string message;
PointEC publicKey;
PointEC ecR;
uint256 s;
}
/**
* @dev Returns the result of schnorr signature verify..
* @param message signed message.
* @param publicKey public key with which message was signed.
* @param ecR signature part R.
* @param s signature part s.
* @return verifying result.
*/
function SchnorrSignatureVerify(
string memory message,
PointEC memory publicKey,
PointEC memory ecR,
uint256 s
) public pure returns (bool) {
uint256 messageHash;
PointEC memory ecG;
PointEC memory ecLeft;
PointEC memory ecRight;
require(
eIsOnCurve(publicKey.x, publicKey.y) && eIsOnCurve(ecR.x, ecR.y),
"Invalid input parametrs to verify the Schnorr signature"
);
// c = H (X, R, m)
messageHash = uint256(
sha256(abi.encodePacked(publicKey.x, publicKey.y, ecR.x, ecR.y, message))
);
//s*G
ecG.x = gx;
ecG.y = gy;
(ecLeft.x, ecLeft.y) = eMul(s, ecG.x, ecG.y);
//R + c*X
(ecRight.x, ecRight.y) = eMul(messageHash, publicKey.x, publicKey.y);
(ecRight.x, ecRight.y) = eAdd(ecRight.x, ecRight.y, ecR.x, ecR.y);
return _equalPointEC(ecLeft, ecRight);
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @dev Interface of the ERC20 standard with burn and mint .
*/
interface IERC20MintableBurnable is IERC20 {
/**
* @dev Burns a specific amount of tokens.
* @param amount The amount of token to be burned.
*/
function burn(uint256 amount) external;
/**
* @dev Function to mint tokens
* @param to The address that will receive the minted tokens.
* @param amount The amount of tokens to mint.
*/
function mint(address to, uint256 amount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
interface IPriceConsumer {
function exchangeAssets(
uint8 exchAggr,
uint8 quoteAggr,
uint256 exchAmount
) external view returns (uint256, uint8);
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ERC20Mock is ERC20 {
constructor(uint256 amount) ERC20("Test Token", "TT") {
_mint(msg.sender, amount);
}
}
\ No newline at end of file
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TestERC20Mock is ERC20 {
constructor(uint256 amount) ERC20("Test Token", "TT") {
_mint(msg.sender, amount);
}
}
\ No newline at end of file
// SPDX-License-Identifier: MIT
pragma solidity =0.8.4;
import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol";
contract TestERC20 is ERC20PresetMinterPauser {
constructor(uint256 amount) ERC20PresetMinterPauser("Test Token", "TT") {
_mint(msg.sender, amount);
}
}
\ No newline at end of file
require ("@nomiclabs/hardhat-waffle");
require ("hardhat-gas-reporter");
require ("hardhat-contract-sizer");
require ("@nomiclabs/hardhat-etherscan");
require ("@nomiclabs/hardhat-ethers");
require ("solidity-coverage");
require("hardhat-gas-reporter");
const dotenv = require('dotenv');
dotenv.config();
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const INFURA_PROJECT_ID = process.env.INFURA_PROJECT_ID;
const COINMARKETCAP_API_KEY = process.env.COINMARKETCAP_API_KEY;
const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY;
module.exports = {
defaultNetwork: "hardhat",
networks: {
hardhat: {
allowUnlimitedContractSize: true,
gas: 30000000
},
ropsten: {
url: "https://ropsten.infura.io/v3/179491410de5450cb20f88593067a22c",
accounts: [`0x${PRIVATE_KEY}`]
},
goerli: {
url: "https://goerli.infura.io/v3/179491410de5450cb20f88593067a22c",
accounts: [`0x${PRIVATE_KEY}`]
},
// localhost: {
// url: "http://127.0.0.1:8545",
// allowUnlimitedContractSize: true,
// },
rinkeby: {
url: `https://rinkeby.infura.io/v3/${INFURA_PROJECT_ID}`,
accounts: [`0x${PRIVATE_KEY}`],
gasPrice: 45000000000,
},
// mainnet: {
// url: `https://mainnet.infura.io/v3/${INFURA_PROJECT_ID}`,
// accounts: [`0x${PRIVATE_KEY}`],
// gasPrice: 45000000000,
// }
},
etherscan: {
// Your API key for Etherscan
// Obtain one at https://etherscan.io/
apiKey: ETHERSCAN_API_KEY
},
solidity: {
compilers: [
{
version: "0.8.4"
},
{
version: "0.6.6",
},
],
settings: {
optimizer: {
enabled: true,
runs: 200
},
evmVersion: 'london'
}
},
mocha: {
timeout: 20000,
},
gasReporter: {
coinmarketcap: COINMARKETCAP_API_KEY,
excludeContracts: ['TestERC20Mock', 'ERC20'],
currency: "USD",
gasPrice: 100,
enabled: true,
},
etherscan: {
apiKey: ETHERSCAN_API_KEY,
},
// contractSizer: {
// alphaSort: true,
// disambiguatePaths: false,
// runOnCompile: true,
// strict: true,
// // only: [':ERC20$'],
// }
};
This diff is collapsed.
{
"name": "offshift-dev",
"version": "1.0.0",
"description": "OffShift protocol",
"main": "hardhat.config",
"type": "commonjs",
"directories": {
"test": "test"
},
"author": "dev",
"license": "MIT",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"solhint": "solhint -f table contracts/**/*.sol",
"prettier": "prettier --write 'contracts/**/*.sol'",
"prettier:solidity": "prettier --write contracts/**/*.sol",
"lint": "prettier --list-different 'contracts/**/*.sol'",
"compile": "npx hardhat size-contracts && npx hardhat compile",
"coverage": "npx hardhat size-contracts && npx hardhat coverage --network hardhat",
"size": "npx hardhat size-contracts"
},
"dependencies": {
"@chainlink/contracts": "^0.4.0",
"@openzeppelin/contracts": "^4.3.0",
"bn.js": "^5.2.0"
},
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^2.1.2",
"@nomiclabs/hardhat-truffle5": "^2.0.0",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@nomiclabs/hardhat-web3": "^2.0.0",
"@types/chai": "^4.2.21",
"@types/chai-as-promised": "^7.1.4",
"@types/mocha": "^8.2.3",
"@types/node": "^16.6.2",
"bip-schnorr": "^0.6.3",
"chai": "^4.3.4",
"dotenv": "^8.6.0",
"elliptic-curve-solidity": "^0.2.4",
"eslint": "^6.8.0",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"ethereum-waffle": "^3.2.0",
"ethers": "^5.4.6",
"hardhat": "^2.6.8",
"hardhat-contract-sizer": "^2.0.3",
"hardhat-gas-reporter": "^1.0.4",
"noble-secp256k1": "^1.2.9",
"prettier": "^2.2.1",
"prettier-plugin-solidity": "^1.0.0-beta.7",
"solhint": "^3.3.4",
"solhint-plugin-prettier": "0.0.5",
"solidity-coverage": "^0.7.16",
"ts-node": "^9.1.1",
"typescript": "^4.2.4",
"web3": "^1.5.2"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vitalii-odnovol/offshift-dev.git"
},
"bugs": {
"url": "https://github.com/vitalii-odnovol/offshift-dev/issues"
},
"homepage": "https://github.com/vitalii-odnovol/offshift-dev#readme"
}
async function main() {
const [deployer] = await ethers.getSigners();
console.log("Deploying contracts with the account:", deployer.address);
console.log("Account balance:", (await deployer.getBalance()).toString());
const PriceConsumer = await ethers.getContractFactory("PriceConsumer");
const priceConsumer = await PriceConsumer.deploy();
await priceConsumer.deployed()
const CommitmentCircuit = await ethers.getContractFactory("CommitmentCircuit");
const commitmentCircuit = await CommitmentCircuit.deploy(
"0x97c35747AbE05EFD38A1Fc081a42600fdfB1e2F1", // xft token address
priceConsumer.address // price consumer address
);
await commitmentCircuit.deployed()
console.log("Price consumer address:", priceConsumer.address);
console.log("Commitment circuit address:", commitmentCircuit.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
// const hre = require("hardhat");
// async function main() {
// const [deployer] = await hre.ethers.getSigners();
// console.log("Deploying contracts with the account:", deployer.address);
// // console.log("Account balance:", (await deployer.getBalance()).toString());
// // await hre.run('compile');
// const PedersenCommitment = await ethers.getContractFactory("PedersenCommitment");
// const pedersenCommitment = await PedersenCommitment.deploy();
// console.log("PedersenCommitment address:", pedersenCommitment.address);
// }
// main()
// .then(() => process.exit(0))
// .catch((error) => {
// console.error(error);
// process.exit(1);
// });
// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
// Runtime Environment's members available in the global scope.
const hre = require("hardhat");
async function main() {
// Hardhat always runs the compile task when running scripts with its command
// line interface.
//
// If this script is run directly using `node` you may want to call compile
// manually to make sure everything is compiled
// await hre.run('compile');
// We get the contract to deploy
// const Greeter = await hre.ethers.getContractFactory("Greeter");
// const greeter = await Greeter.deploy("Hello, Hardhat!");
// await greeter.deployed();
// console.log("Greeter deployed to:", greeter.address);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment