From fa7ab7a60b4d2f707b10fc6503b1820402fe7100 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Mon, 7 Oct 2024 20:35:10 +0300 Subject: [PATCH 01/45] init stack & big int --- contracts/mock/utils/StackMock.sol | 58 ++ contracts/utils/BigNumbers.sol | 1309 ++++++++++++++++++++++++++++ contracts/utils/MemoryBigInt.sol | 79 ++ contracts/utils/MemoryStack.sol | 143 +++ test/utils/Stack.test.ts | 27 + 5 files changed, 1616 insertions(+) create mode 100644 contracts/mock/utils/StackMock.sol create mode 100644 contracts/utils/BigNumbers.sol create mode 100644 contracts/utils/MemoryBigInt.sol create mode 100644 contracts/utils/MemoryStack.sol create mode 100644 test/utils/Stack.test.ts diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol new file mode 100644 index 0000000..77c730d --- /dev/null +++ b/contracts/mock/utils/StackMock.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import "../../utils/MemoryStack.sol"; +import "../../utils/MemoryBigInt.sol"; +import "hardhat/console.sol"; + +contract StackMock { + using MemoryStack for MemoryStack.Stack; + using MemoryBigInt for *; + + //// let t: bigint; + //// let u: bigint; + //// let v: bigint; + //// let w: bigint; + //// + //// if (isZeroCurve(x0, y0)) { + //// return zeroProj(); + //// } + //// + //// u = modmul(y0, z0, p); + //// u = modmul(u, 2n, p); + //// + //// v = modmul(u, x0, p); + //// v = modmul(v, y0, p); + //// v = modmul(v, 2n, p); + //// + //// x0 = modmul(x0, x0, p); + //// t = modmul(x0, BigInt(3), p); + //// + //// z0 = modmul(z0, z0, p); + //// z0 = modmul(z0, a, p); + //// t = (t + z0) % p; + //// + //// w = modmul(t, t, p); + //// x0 = modmul(2n, v, p); + //// w = (w + (p - x0)) % p; + //// + //// x0 = (v + (p - w)) % p; + //// x0 = modmul(t, x0, p); + //// y0 = modmul(y0, u, p); + //// y0 = modmul(y0, y0, p); + //// y0 = modmul(2n, y0, p); + //// let y1 = (x0 + (p - y0)) % p; + //// + //// let x1 = modmul(u, w, p); + //// + //// let z1 = modmul(u, u, p); + //// z1 = modmul(z1, u, p); + //// + function mock() external view returns (MemoryBigInt.BigInt memory) { + MemoryBigInt.Heap memory heap_ = MemoryBigInt.initHeap(64); + + MemoryBigInt.BigInt memory a_ = heap_.initBigInt(hex"1337"); + + return a_; + } +} diff --git a/contracts/utils/BigNumbers.sol b/contracts/utils/BigNumbers.sol new file mode 100644 index 0000000..4410753 --- /dev/null +++ b/contracts/utils/BigNumbers.sol @@ -0,0 +1,1309 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +//// Definition here allows both the lib and inheriting contracts to use BigNumber directly. +// struct BigNumber { +// bytes val; +// bool neg; +// uint bitlen; +// } +// +///** +// * @notice BigNumbers library for Solidity. +// */ +//library BigNumbers { +// +// /// @notice the value for number 0 of a BigNumber instance. +// bytes constant ZERO = hex"0000000000000000000000000000000000000000000000000000000000000000"; +// /// @notice the value for number 1 of a BigNumber instance. +// bytes constant ONE = hex"0000000000000000000000000000000000000000000000000000000000000001"; +// /// @notice the value for number 2 of a BigNumber instance. +// bytes constant TWO = hex"0000000000000000000000000000000000000000000000000000000000000002"; +// +// // ***************** BEGIN EXPOSED MANAGEMENT FUNCTIONS ****************** +// /** @notice verify a BN instance +// * @dev checks if the BN is in the correct format. operations should only be carried out on +// * verified BNs, so it is necessary to call this if your function takes an arbitrary BN +// * as input. +// * +// * @param bn BigNumber instance +// */ +// function verify( +// BigNumber memory bn +// ) public pure { +// uint msword; +// bytes memory val = bn.val; +// assembly {msword := mload(add(val,0x20))} //get msword of result +// if(msword==0) require(isZero(bn)); +// else require((bn.val.length % 32 == 0) && (msword>>((bn.bitlen-1)%256)==1)); +// } +// +// /** @notice initialize a BN instance +// * @dev wrapper function for _init. initializes from bytes value. +// * Allows passing bitLength of value. This is NOT verified in the public function. Only use where bitlen is +// * explicitly known; otherwise use the other init function. +// * +// * @param val BN value. may be of any size. +// * @param neg neg whether the BN is +/- +// * @param bitlen bit length of output. +// * @return BigNumber instance +// */ +// function init( +// bytes memory val, +// bool neg, +// uint bitlen +// ) public view returns(BigNumber memory){ +// return _init(val, neg, bitlen); +// } +// +// /** @notice initialize a BN instance +// * @dev wrapper function for _init. initializes from bytes value. +// * +// * @param val BN value. may be of any size. +// * @param neg neg whether the BN is +/- +// * @return BigNumber instance +// */ +// function init( +// bytes memory val, +// bool neg +// ) public view returns(BigNumber memory){ +// return _init(val, neg, 0); +// } +// +// /** @notice initialize a BN instance +// * @dev wrapper function for _init. initializes from uint value (converts to bytes); +// * tf. resulting BN is in the range -2^256-1 ... 2^256-1. +// * +// * @param val uint value. +// * @param neg neg whether the BN is +/- +// * @return BigNumber instance +// */ +// function init( +// uint val, +// bool neg +// ) public view returns(BigNumber memory){ +// return _init(abi.encodePacked(val), neg, 0); +// } +// // ***************** END EXPOSED MANAGEMENT FUNCTIONS ****************** +// +// +// +// +// // ***************** BEGIN EXPOSED CORE CALCULATION FUNCTIONS ****************** +// /** @notice BigNumber addition: a + b. +// * @dev add: Initially prepare BigNumbers for addition operation; internally calls actual addition/subtraction, +// * depending on inputs. +// * In order to do correct addition or subtraction we have to handle the sign. +// * This function discovers the sign of the result based on the inputs, and calls the correct operation. +// * +// * @param a first BN +// * @param b second BN +// * @return r result - addition of a and b. +// */ +// function add( +// BigNumber memory a, +// BigNumber memory b +// ) public pure returns(BigNumber memory r) { +// if(a.bitlen==0 && b.bitlen==0) return zero(); +// if(a.bitlen==0) return b; +// if(b.bitlen==0) return a; +// bytes memory val; +// uint bitlen; +// int compare = cmp(a,b,false); +// +// if(a.neg || b.neg){ +// if(a.neg && b.neg){ +// if(compare>=0) (val, bitlen) = _add(a.val,b.val,a.bitlen); +// else (val, bitlen) = _add(b.val,a.val,b.bitlen); +// r.neg = true; +// } +// else { +// if(compare==1){ +// (val, bitlen) = _sub(a.val,b.val); +// r.neg = a.neg; +// } +// else if(compare==-1){ +// (val, bitlen) = _sub(b.val,a.val); +// r.neg = !a.neg; +// } +// else return zero();//one pos and one neg, and same value. +// } +// } +// else{ +// if(compare>=0){ // a>=b +// (val, bitlen) = _add(a.val,b.val,a.bitlen); +// } +// else { +// (val, bitlen) = _add(b.val,a.val,b.bitlen); +// } +// r.neg = false; +// } +// +// r.val = val; +// r.bitlen = (bitlen); +// } +// +// /** @notice BigNumber subtraction: a - b. +// * @dev sub: Initially prepare BigNumbers for subtraction operation; internally calls actual addition/subtraction, +// depending on inputs. +// * In order to do correct addition or subtraction we have to handle the sign. +// * This function discovers the sign of the result based on the inputs, and calls the correct operation. +// * +// * @param a first BN +// * @param b second BN +// * @return r result - subtraction of a and b. +// */ +// function sub( +// BigNumber memory a, +// BigNumber memory b +// ) public pure returns(BigNumber memory r) { +// if(a.bitlen==0 && b.bitlen==0) return zero(); +// bytes memory val; +// int compare; +// uint bitlen; +// compare = cmp(a,b,false); +// if(a.neg || b.neg) { +// if(a.neg && b.neg){ +// if(compare == 1) { +// (val,bitlen) = _sub(a.val,b.val); +// r.neg = true; +// } +// else if(compare == -1) { +// +// (val,bitlen) = _sub(b.val,a.val); +// r.neg = false; +// } +// else return zero(); +// } +// else { +// if(compare >= 0) (val,bitlen) = _add(a.val,b.val,a.bitlen); +// else (val,bitlen) = _add(b.val,a.val,b.bitlen); +// +// r.neg = (a.neg) ? true : false; +// } +// } +// else { +// if(compare == 1) { +// (val,bitlen) = _sub(a.val,b.val); +// r.neg = false; +// } +// else if(compare == -1) { +// (val,bitlen) = _sub(b.val,a.val); +// r.neg = true; +// } +// else return zero(); +// } +// +// r.val = val; +// r.bitlen = (bitlen); +// } +// +// /** @notice BigNumber multiplication: a * b. +// * @dev mul: takes two BigNumbers and multiplys them. Order is irrelevant. +// * multiplication achieved using modexp precompile: +// * (a * b) = ((a + b)**2 - (a - b)**2) / 4 +// * +// * @param a first BN +// * @param b second BN +// * @return r result - multiplication of a and b. +// */ +// function mul( +// BigNumber memory a, +// BigNumber memory b +// ) public view returns(BigNumber memory r){ +// +// BigNumber memory lhs = add(a,b); +// BigNumber memory fst = modexp(lhs, two(), _powModulus(lhs, 2)); // (a+b)^2 +// +// // no need to do subtraction part of the equation if a == b; if so, it has no effect on final result. +// if(!eq(a,b)) { +// BigNumber memory rhs = sub(a,b); +// BigNumber memory snd = modexp(rhs, two(), _powModulus(rhs, 2)); // (a-b)^2 +// r = _shr(sub(fst, snd) , 2); // (a * b) = (((a + b)**2 - (a - b)**2) / 4 +// } +// else { +// r = _shr(fst, 2); // a==b ? (((a + b)**2 / 4 +// } +// } +// +// /** @notice BigNumber division verification: a * b. +// * @dev div: takes three BigNumbers (a,b and result), and verifies that a/b == result. +// * Performing BigNumber division on-chain is a significantly expensive operation. As a result, +// * we expose the ability to verify the result of a division operation, which is a constant time operation. +// * (a/b = result) == (a = b * result) +// * Integer division only; therefore: +// * verify ((b*result) + (a % (b*result))) == a. +// * eg. 17/7 == 2: +// * verify (7*2) + (17 % (7*2)) == 17. +// * The function returns a bool on successful verification. The require statements will ensure that false can never +// * be returned, however inheriting contracts may also want to put this function inside a require statement. +// * +// * @param a first BigNumber +// * @param b second BigNumber +// * @param r result BigNumber +// * @return bool whether or not the operation was verified +// */ +// function divVerify( +// BigNumber memory a, +// BigNumber memory b, +// BigNumber memory r +// ) public view returns(bool) { +// +// // first do zero check. +// // if ab. +// * +// * @param a BigNumber +// * @param b BigNumber +// * @param signed whether to consider sign of inputs +// * @return int result +// */ +// function cmp( +// BigNumber memory a, +// BigNumber memory b, +// bool signed +// ) public pure returns(int){ +// int trigger = 1; +// if(signed){ +// if(a.neg && b.neg) trigger = -1; +// else if(a.neg==false && b.neg==true) return 1; +// else if(a.neg==true && b.neg==false) return -1; +// } +// +// if(a.bitlen>b.bitlen) return trigger; // 1*trigger +// if(b.bitlen>a.bitlen) return -1*trigger; +// +// uint a_ptr; +// uint b_ptr; +// uint a_word; +// uint b_word; +// +// uint len = a.val.length; //bitlen is same so no need to check length. +// +// assembly{ +// a_ptr := add(mload(a),0x20) +// b_ptr := add(mload(b),0x20) +// } +// +// for(uint i=0; ib_word) return trigger; // 1*trigger +// if(b_word>a_word) return -1*trigger; +// +// } +// +// return 0; //same value. +// } +// +// /** @notice BigNumber equality +// * @dev eq: returns true if a==b. sign always considered. +// * +// * @param a BigNumber +// * @param b BigNumber +// * @return boolean result +// */ +// function eq( +// BigNumber memory a, +// BigNumber memory b +// ) public pure returns(bool){ +// int result = cmp(a, b, true); +// return (result==0) ? true : false; +// } +// +// /** @notice BigNumber greater than +// * @dev eq: returns true if a>b. sign always considered. +// * +// * @param a BigNumber +// * @param b BigNumber +// * @return boolean result +// */ +// function gt( +// BigNumber memory a, +// BigNumber memory b +// ) public pure returns(bool){ +// int result = cmp(a, b, true); +// return (result==1) ? true : false; +// } +// +// /** @notice BigNumber greater than or equal to +// * @dev eq: returns true if a>=b. sign always considered. +// * +// * @param a BigNumber +// * @param b BigNumber +// * @return boolean result +// */ +// function gte( +// BigNumber memory a, +// BigNumber memory b +// ) public pure returns(bool){ +// int result = cmp(a, b, true); +// return (result==1 || result==0) ? true : false; +// } +// +// /** @notice BigNumber less than +// * @dev eq: returns true if a= the bitlength of the value the result is always 0 +// if(bits >= bn.bitlen) return BigNumber(ZERO,false,0); +// +// // set bitlen initially as we will be potentially modifying 'bits' +// bn.bitlen = bn.bitlen-(bits); +// +// // handle shifts greater than 256: +// // if bits is greater than 256 we can simply remove any trailing words, by altering the BN length. +// // we also update 'bits' so that it is now in the range 0..256. +// assembly { +// if or(gt(bits, 0x100), eq(bits, 0x100)) { +// length := sub(length, mul(div(bits, 0x100), 0x20)) +// mstore(mload(bn), length) +// bits := mod(bits, 0x100) +// } +// +// // if bits is multiple of 8 (byte size), we can simply use identity precompile for cheap memcopy. +// // otherwise we shift each word, starting at the least signifcant word, one-by-one using the mask technique. +// // TODO it is possible to do this without the last two operations, see SHL identity copy. +// let bn_val_ptr := mload(bn) +// switch eq(mod(bits, 8), 0) +// case 1 { +// let bytes_shift := div(bits, 8) +// let in := mload(bn) +// let inlength := mload(in) +// let insize := add(inlength, 0x20) +// let out := add(in, bytes_shift) +// let outsize := sub(insize, bytes_shift) +// let success := staticcall(450, 0x4, in, insize, out, insize) +// mstore8(add(out, 0x1f), 0) // maintain our BN layout following identity call: +// mstore(in, inlength) // set current length byte to 0, and reset old length. +// } +// default { +// let mask +// let lsw +// let mask_shift := sub(0x100, bits) +// let lsw_ptr := add(bn_val_ptr, length) +// for { let i := length } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) +// switch eq(i,0x20) // if i==32: +// case 1 { mask := 0 } // - handles lsword: no mask needed. +// default { mask := mload(sub(lsw_ptr,0x20)) } // - else get mask (previous word) +// lsw := shr(bits, mload(lsw_ptr)) // right shift current by bits +// mask := shl(mask_shift, mask) // left shift next significant word by mask_shift +// mstore(lsw_ptr, or(lsw,mask)) // store OR'd mask and shifted bits in-place +// lsw_ptr := sub(lsw_ptr, 0x20) // point to next bits. +// } +// } +// +// // The following removes the leading word containing all zeroes in the result should it exist, +// // as well as updating lengths and pointers as necessary. +// let msw_ptr := add(bn_val_ptr,0x20) +// switch eq(mload(msw_ptr), 0) +// case 1 { +// mstore(msw_ptr, sub(mload(bn_val_ptr), 0x20)) // store new length in new position +// mstore(bn, msw_ptr) // update pointer from bn +// } +// default {} +// } +// +// +// return bn; +// } +// +// /** @notice left shift BigNumber value +// * @dev shr: left shift BigNumber a by 'bits' bits. +// ensures the value is not negative before calling the private function. +// * @param a BigNumber value to shift +// * @param bits amount of bits to shift by +// * @return result BigNumber +// */ +// function shl( +// BigNumber memory a, +// uint bits +// ) public view returns(BigNumber memory){ +// require(!a.neg); +// return _shl(a, bits); +// } +// +// /** @notice sha3 hash a BigNumber. +// * @dev hash: takes a BigNumber and performs sha3 hash on it. +// * we hash each BigNumber WITHOUT it's first word - first word is a pointer to the start of the bytes value, +// * and so is different for each struct. +// * +// * @param a BigNumber +// * @return h bytes32 hash. +// */ +// function hash( +// BigNumber memory a +// ) public pure returns(bytes32 h) { +// //amount of words to hash = all words of the value and three extra words: neg, bitlen & value length. +// assembly { +// h := keccak256( add(a,0x20), add (mload(mload(a)), 0x60 ) ) +// } +// } +// +// /** @notice BigNumber full zero check +// * @dev isZero: checks if the BigNumber is in the default zero format for BNs (ie. the result from zero()). +// * +// * @param a BigNumber +// * @return boolean result. +// */ +// function isZero( +// BigNumber memory a +// ) public pure returns(bool) { +// return isZero(a.val) && a.val.length==0x20 && !a.neg && a.bitlen == 0; +// } +// +// +// /** @notice bytes zero check +// * @dev isZero: checks if input bytes value resolves to zero. +// * +// * @param a bytes value +// * @return boolean result. +// */ +// function isZero( +// bytes memory a +// ) public pure returns(bool) { +// uint msword; +// uint msword_ptr; +// assembly { +// msword_ptr := add(a,0x20) +// } +// for(uint i=0; i 0) return false; +// assembly { msword_ptr := add(msword_ptr, 0x20) } +// } +// return true; +// +// } +// +// /** @notice BigNumber value bit length +// * @dev bitLength: returns BigNumber value bit length- ie. log2 (most significant bit of value) +// * +// * @param a BigNumber +// * @return uint bit length result. +// */ +// function bitLength( +// BigNumber memory a +// ) public pure returns(uint){ +// return bitLength(a.val); +// } +// +// /** @notice bytes bit length +// * @dev bitLength: returns bytes bit length- ie. log2 (most significant bit of value) +// * +// * @param a bytes value +// * @return r uint bit length result. +// */ +// function bitLength( +// bytes memory a +// ) public pure returns(uint r){ +// if(isZero(a)) return 0; +// uint msword; +// assembly { +// msword := mload(add(a,0x20)) // get msword of input +// } +// r = bitLength(msword); // get bitlen of msword, add to size of remaining words. +// assembly { +// r := add(r, mul(sub(mload(a), 0x20) , 8)) // res += (val.length-32)*8; +// } +// } +// +// /** @notice uint bit length +// @dev bitLength: get the bit length of a uint input - ie. log2 (most significant bit of 256 bit value (one EVM word)) +// * credit: Tjaden Hess @ ethereum.stackexchange +// * @param a uint value +// * @return r uint bit length result. +// */ +// function bitLength( +// uint a +// ) public pure returns (uint r){ +// assembly { +// switch eq(a, 0) +// case 1 { +// r := 0 +// } +// default { +// let arg := a +// a := sub(a,1) +// a := or(a, div(a, 0x02)) +// a := or(a, div(a, 0x04)) +// a := or(a, div(a, 0x10)) +// a := or(a, div(a, 0x100)) +// a := or(a, div(a, 0x10000)) +// a := or(a, div(a, 0x100000000)) +// a := or(a, div(a, 0x10000000000000000)) +// a := or(a, div(a, 0x100000000000000000000000000000000)) +// a := add(a, 1) +// let m := mload(0x40) +// mstore(m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd) +// mstore(add(m,0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe) +// mstore(add(m,0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616) +// mstore(add(m,0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff) +// mstore(add(m,0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e) +// mstore(add(m,0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707) +// mstore(add(m,0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606) +// mstore(add(m,0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100) +// mstore(0x40, add(m, 0x100)) +// let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff +// let shift := 0x100000000000000000000000000000000000000000000000000000000000000 +// let _a := div(mul(a, magic), shift) +// r := div(mload(add(m,sub(255,_a))), shift) +// r := add(r, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000))) +// // where a is a power of two, result needs to be incremented. we use the power of two trick here: if(arg & arg-1 == 0) ++r; +// if eq(and(arg, sub(arg, 1)), 0) { +// r := add(r, 1) +// } +// } +// } +// } +// +// /** @notice BigNumber zero value +// @dev zero: returns zero encoded as a BigNumber +// * @return zero encoded as BigNumber +// */ +// function zero( +// ) public pure returns(BigNumber memory) { +// return BigNumber(ZERO, false, 0); +// } +// +// /** @notice BigNumber one value +// @dev one: returns one encoded as a BigNumber +// * @return one encoded as BigNumber +// */ +// function one( +// ) public pure returns(BigNumber memory) { +// return BigNumber(ONE, false, 1); +// } +// +// /** @notice BigNumber two value +// @dev two: returns two encoded as a BigNumber +// * @return two encoded as BigNumber +// */ +// function two( +// ) public pure returns(BigNumber memory) { +// return BigNumber(TWO, false, 2); +// } +// // ***************** END EXPOSED HELPER FUNCTIONS ****************** +// +// +// +// +// +// // ***************** START PRIVATE MANAGEMENT FUNCTIONS ****************** +// /** @notice Create a new BigNumber. +// @dev init: overloading allows caller to obtionally pass bitlen where it is known - as it is cheaper to do off-chain and verify on-chain. +// * we assert input is in data structure as defined above, and that bitlen, if passed, is correct. +// * 'copy' parameter indicates whether or not to copy the contents of val to a new location in memory (for example where you pass +// * the contents of another variable's value in) +// * @param val bytes - bignum value. +// * @param neg bool - sign of value +// * @param bitlen uint - bit length of value +// * @return r BigNumber initialized value. +// */ +// function _init( +// bytes memory val, +// bool neg, +// uint bitlen +// ) private view returns(BigNumber memory r){ +// // use identity at location 0x4 for cheap memcpy. +// // grab contents of val, load starting from memory end, update memory end pointer. +// assembly { +// let data := add(val, 0x20) +// let length := mload(val) +// let out +// let freemem := mload(0x40) +// switch eq(mod(length, 0x20), 0) // if(val.length % 32 == 0) +// case 1 { +// out := add(freemem, 0x20) // freememory location + length word +// mstore(freemem, length) // set new length +// } +// default { +// let offset := sub(0x20, mod(length, 0x20)) // offset: 32 - (length % 32) +// out := add(add(freemem, offset), 0x20) // freememory location + offset + length word +// mstore(freemem, add(length, offset)) // set new length +// } +// pop(staticcall(450, 0x4, data, length, out, length)) // copy into 'out' memory location +// mstore(0x40, add(freemem, add(mload(freemem), 0x20))) // update the free memory pointer +// +// // handle leading zero words. assume freemem is pointer to bytes value +// let bn_length := mload(freemem) +// for { } eq ( eq(bn_length, 0x20), 0) { } { // for(; length!=32; length-=32) +// switch eq(mload(add(freemem, 0x20)),0) // if(msword==0): +// case 1 { freemem := add(freemem, 0x20) } // update length pointer +// default { break } // else: loop termination. non-zero word found +// bn_length := sub(bn_length,0x20) +// } +// mstore(freemem, bn_length) +// +// mstore(r, freemem) // store new bytes value in r +// mstore(add(r, 0x20), neg) // store neg value in r +// } +// +// r.bitlen = bitlen == 0 ? bitLength(r.val) : bitlen; +// } +// // ***************** END PRIVATE MANAGEMENT FUNCTIONS ****************** +// +// +// +// +// +// // ***************** START PRIVATE CORE CALCULATION FUNCTIONS ****************** +// /** @notice takes two BigNumber memory values and the bitlen of the max value, and adds them. +// * @dev _add: This function is private and only callable from add: therefore the values may be of different sizes, +// * in any order of size, and of different signs (handled in add). +// * As values may be of different sizes, inputs are considered starting from the least significant +// * words, working back. +// * The function calculates the new bitlen (basically if bitlens are the same for max and min, +// * max_bitlen++) and returns a new BigNumber memory value. +// * +// * @param max bytes - biggest value (determined from add) +// * @param min bytes - smallest value (determined from add) +// * @param max_bitlen uint - bit length of max value. +// * @return bytes result - max + min. +// * @return uint - bit length of result. +// */ +// function _add( +// bytes memory max, +// bytes memory min, +// uint max_bitlen +// ) private pure returns (bytes memory, uint) { +// bytes memory result; +// assembly { +// +// let result_start := mload(0x40) // Get the highest available block of memory +// let carry := 0 +// let uint_max := sub(0,1) +// +// let max_ptr := add(max, mload(max)) +// let min_ptr := add(min, mload(min)) // point to last word of each byte array. +// +// let result_ptr := add(add(result_start,0x20), mload(max)) // set result_ptr end. +// +// for { let i := mload(max) } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) +// let max_val := mload(max_ptr) // get next word for 'max' +// switch gt(i,sub(mload(max),mload(min))) // if(i>(max_length-min_length)). while +// // 'min' words are still available. +// case 1{ +// let min_val := mload(min_ptr) // get next word for 'min' +// mstore(result_ptr, add(add(max_val,min_val),carry)) // result_word = max_word+min_word+carry +// switch gt(max_val, sub(uint_max,sub(min_val,carry))) // this switch block finds whether or +// // not to set the carry bit for the +// // next iteration. +// case 1 { carry := 1 } +// default { +// switch and(eq(max_val,uint_max),or(gt(carry,0), gt(min_val,0))) +// case 1 { carry := 1 } +// default{ carry := 0 } +// } +// +// min_ptr := sub(min_ptr,0x20) // point to next 'min' word +// } +// default{ // else: remainder after 'min' words are complete. +// mstore(result_ptr, add(max_val,carry)) // result_word = max_word+carry +// +// switch and( eq(uint_max,max_val), eq(carry,1) ) // this switch block finds whether or +// // not to set the carry bit for the +// // next iteration. +// case 1 { carry := 1 } +// default { carry := 0 } +// } +// result_ptr := sub(result_ptr,0x20) // point to next 'result' word +// max_ptr := sub(max_ptr,0x20) // point to next 'max' word +// } +// +// switch eq(carry,0) +// case 1{ result_start := add(result_start,0x20) } // if carry is 0, increment result_start, ie. +// // length word for result is now one word +// // position ahead. +// default { mstore(result_ptr, 1) } // else if carry is 1, store 1; overflow has +// // occured, so length word remains in the +// // same position. +// +// result := result_start // point 'result' bytes value to the correct +// // address in memory. +// mstore(result,add(mload(max),mul(0x20,carry))) // store length of result. we are finished +// // with the byte array. +// +// mstore(0x40, add(result,add(mload(result),0x20))) // Update freemem pointer to point to new +// // end of memory. +// +// // we now calculate the result's bit length. +// // with addition, if we assume that some a is at least equal to some b, then the resulting bit length will +// // be a's bit length or (a's bit length)+1, depending on carry bit.this is cheaper than calling bitLength. +// let msword := mload(add(result,0x20)) // get most significant word of result +// // if(msword==1 || msword>>(max_bitlen % 256)==1): +// if or( eq(msword, 1), eq(shr(mod(max_bitlen,256),msword),1) ) { +// max_bitlen := add(max_bitlen, 1) // if msword's bit length is 1 greater +// // than max_bitlen, OR overflow occured, +// // new bitlen is max_bitlen+1. +// } +// } +// +// +// return (result, max_bitlen); +// } +// +// /** @notice takes two BigNumber memory values and subtracts them. +// * @dev _sub: This function is private and only callable from add: therefore the values may be of different sizes, +// * in any order of size, and of different signs (handled in add). +// * As values may be of different sizes, inputs are considered starting from the least significant words, +// * working back. +// * The function calculates the new bitlen (basically if bitlens are the same for max and min, +// * max_bitlen++) and returns a new BigNumber memory value. +// * +// * @param max bytes - biggest value (determined from add) +// * @param min bytes - smallest value (determined from add) +// * @return bytes result - max + min. +// * @return uint - bit length of result. +// */ +// function _sub( +// bytes memory max, +// bytes memory min +// ) public pure returns (bytes memory, uint) { +// bytes memory result; +// uint carry = 0; +// uint uint_max = type(uint256).max; +// assembly { +// +// let result_start := mload(0x40) // Get the highest available block of +// // memory +// +// let max_len := mload(max) +// let min_len := mload(min) // load lengths of inputs +// +// let len_diff := sub(max_len,min_len) // get differences in lengths. +// +// let max_ptr := add(max, max_len) +// let min_ptr := add(min, min_len) // go to end of arrays +// let result_ptr := add(result_start, max_len) // point to least significant result +// // word. +// let memory_end := add(result_ptr,0x20) // save memory_end to update free memory +// // pointer at the end. +// +// for { let i := max_len } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) +// let max_val := mload(max_ptr) // get next word for 'max' +// switch gt(i,len_diff) // if(i>(max_length-min_length)). while +// // 'min' words are still available. +// case 1{ +// let min_val := mload(min_ptr) // get next word for 'min' +// +// mstore(result_ptr, sub(sub(max_val,min_val),carry)) // result_word = (max_word-min_word)-carry +// /// max_val < min_val + carry || (min_val == uint256_max) && carry == 1 +// switch or(lt(max_val, add(min_val,carry)), +// and(eq(min_val,uint_max), eq(carry,1))) // this switch block finds whether or +// // not to set the carry bit for the next iteration. +// case 1 { carry := 1 } +// default { carry := 0 } +// +// min_ptr := sub(min_ptr,0x20) // point to next 'result' word +// } +// default { // else: remainder after 'min' words are complete. +// +// mstore(result_ptr, sub(max_val,carry)) // result_word = max_word-carry +// +// switch and( eq(max_val,0), eq(carry,1) ) // this switch block finds whether or +// // not to set the carry bit for the +// // next iteration. +// case 1 { carry := 1 } +// default { carry := 0 } +// +// } +// result_ptr := sub(result_ptr,0x20) // point to next 'result' word +// max_ptr := sub(max_ptr,0x20) // point to next 'max' word +// } +// +// //the following code removes any leading words containing all zeroes in the result. +// result_ptr := add(result_ptr,0x20) +// +// // for(result_ptr+=32;; result==0; result_ptr+=32) +// for { } eq(mload(result_ptr), 0) { result_ptr := add(result_ptr,0x20) } { +// result_start := add(result_start, 0x20) // push up the start pointer for the result +// max_len := sub(max_len,0x20) // subtract a word (32 bytes) from the +// // result length. +// } +// +// result := result_start // point 'result' bytes value to +// // the correct address in memory +// +// mstore(result,max_len) // store length of result. we +// // are finished with the byte array. +// +// mstore(0x40, memory_end) // Update freemem pointer. +// } +// +// uint new_bitlen = bitLength(result); // calculate the result's +// // bit length. +// +// return (result, new_bitlen); +// } +// +// /** @notice gets the modulus value necessary for calculating exponetiation. +// * @dev _powModulus: we must pass the minimum modulus value which would return JUST the a^b part of the calculation +// * in modexp. the rationale here is: +// * if 'a' has n bits, then a^e has at most n*e bits. +// * using this modulus in exponetiation will result in simply a^e. +// * therefore the value may be many words long. +// * This is done by: +// * - storing total modulus byte length +// * - storing first word of modulus with correct bit set +// * - updating the free memory pointer to come after total length. +// * +// * @param a BigNumber base +// * @param e uint exponent +// * @return BigNumber modulus result +// */ +// function _powModulus( +// BigNumber memory a, +// uint e +// ) private pure returns(BigNumber memory){ +// bytes memory _modulus = ZERO; +// uint mod_index; +// +// assembly { +// mod_index := mul(mload(add(a, 0x40)), e) // a.bitlen * e is the max bitlength of result +// let first_word_modulus := shl(mod(mod_index, 256), 1) // set bit in first modulus word. +// mstore(_modulus, mul(add(div(mod_index,256),1),0x20)) // store length of modulus +// mstore(add(_modulus,0x20), first_word_modulus) // set first modulus word +// mstore(0x40, add(_modulus, add(mload(_modulus),0x20))) // update freemem pointer to be modulus index +// // + length +// } +// +// //create modulus BigNumber memory for modexp function +// return BigNumber(_modulus, false, mod_index); +// } +// +// /** @notice Modular Exponentiation: Takes bytes values for base, exp, mod and calls precompile for (base^exp)%^mod +// * @dev modexp: Wrapper for built-in modexp (contract 0x5) as described here: +// * https://github.com/ethereum/EIPs/pull/198 +// * +// * @param _b bytes base +// * @param _e bytes base_inverse +// * @param _m bytes exponent +// * @param r bytes result. +// */ +// function _modexp( +// bytes memory _b, +// bytes memory _e, +// bytes memory _m +// ) private view returns(bytes memory r) { +// assembly { +// +// let bl := mload(_b) +// let el := mload(_e) +// let ml := mload(_m) +// +// +// let freemem := mload(0x40) // Free memory pointer is always stored at 0x40 +// +// +// mstore(freemem, bl) // arg[0] = base.length @ +0 +// +// mstore(add(freemem,32), el) // arg[1] = exp.length @ +32 +// +// mstore(add(freemem,64), ml) // arg[2] = mod.length @ +64 +// +// // arg[3] = base.bits @ + 96 +// // Use identity built-in (contract 0x4) as a cheap memcpy +// let success := staticcall(450, 0x4, add(_b,32), bl, add(freemem,96), bl) +// +// // arg[4] = exp.bits @ +96+base.length +// let size := add(96, bl) +// success := staticcall(450, 0x4, add(_e,32), el, add(freemem,size), el) +// +// // arg[5] = mod.bits @ +96+base.length+exp.length +// size := add(size,el) +// success := staticcall(450, 0x4, add(_m,32), ml, add(freemem,size), ml) +// +// switch success case 0 { invalid() } //fail where we haven't enough gas to make the call +// +// // Total size of input = 96+base.length+exp.length+mod.length +// size := add(size,ml) +// // Invoke contract 0x5, put return value right after mod.length, @ +96 +// success := staticcall(sub(gas(), 1350), 0x5, freemem, size, add(freemem, 0x60), ml) +// +// switch success case 0 { invalid() } //fail where we haven't enough gas to make the call +// +// let length := ml +// let msword_ptr := add(freemem, 0x60) +// +// ///the following code removes any leading words containing all zeroes in the result. +// for { } eq ( eq(length, 0x20), 0) { } { // for(; length!=32; length-=32) +// switch eq(mload(msword_ptr),0) // if(msword==0): +// case 1 { msword_ptr := add(msword_ptr, 0x20) } // update length pointer +// default { break } // else: loop termination. non-zero word found +// length := sub(length,0x20) +// } +// r := sub(msword_ptr,0x20) +// mstore(r, length) +// +// // point to the location of the return value (length, bits) +// //assuming mod length is multiple of 32, return value is already in the right format. +// mstore(0x40, add(add(96, freemem),ml)) //deallocate freemem pointer +// } +// } +// // ***************** END PRIVATE CORE CALCULATION FUNCTIONS ****************** +// +// +// +// +// +// // ***************** START PRIVATE HELPER FUNCTIONS ****************** +// /** @notice left shift BigNumber memory 'dividend' by 'value' bits. +// * @param bn value to shift +// * @param bits amount of bits to shift by +// * @return r result +// */ +// function _shl( +// BigNumber memory bn, +// uint bits +// ) private view returns(BigNumber memory r) { +// if(bits==0 || bn.bitlen==0) return bn; +// +// // we start by creating an empty bytes array of the size of the output, based on 'bits'. +// // for that we must get the amount of extra words needed for the output. +// uint length = bn.val.length; +// // position of bitlen in most significnat word +// uint bit_position = ((bn.bitlen-1) % 256) + 1; +// // total extra words. we check if the bits remainder will add one more word. +// uint extra_words = (bits / 256) + ( (bits % 256) >= (256 - bit_position) ? 1 : 0); +// // length of output +// uint total_length = length + (extra_words * 0x20); +// +// r.bitlen = bn.bitlen+(bits); +// r.neg = bn.neg; +// bits %= 256; +// +// +// bytes memory bn_shift; +// uint bn_shift_ptr; +// // the following efficiently creates an empty byte array of size 'total_length' +// assembly { +// let freemem_ptr := mload(0x40) // get pointer to free memory +// mstore(freemem_ptr, total_length) // store bytes length +// let mem_end := add(freemem_ptr, total_length) // end of memory +// mstore(mem_end, 0) // store 0 at memory end +// bn_shift := freemem_ptr // set pointer to bytes +// bn_shift_ptr := add(bn_shift, 0x20) // get bn_shift pointer +// mstore(0x40, add(mem_end, 0x20)) // update freemem pointer +// } +// +// // use identity for cheap copy if bits is multiple of 8. +// if(bits % 8 == 0) { +// // calculate the position of the first byte in the result. +// uint bytes_pos = ((256-(((bn.bitlen-1)+bits) % 256))-1) / 8; +// uint insize = (bn.bitlen / 8) + ((bn.bitlen % 8 != 0) ? 1 : 0); +// assembly { +// let in := add(add(mload(bn), 0x20), div(sub(256, bit_position), 8)) +// let out := add(bn_shift_ptr, bytes_pos) +// let success := staticcall(450, 0x4, in, insize, out, length) +// } +// r.val = bn_shift; +// return r; +// } +// +// +// uint mask; +// uint mask_shift = 0x100-bits; +// uint msw; +// uint msw_ptr; +// +// assembly { +// msw_ptr := add(mload(bn), 0x20) +// } +// +// // handle first word before loop if the shift adds any extra words. +// // the loop would handle it if the bit shift doesn't wrap into the next word, +// // so we check only for that condition. +// if((bit_position+bits) > 256){ +// assembly { +// msw := mload(msw_ptr) +// mstore(bn_shift_ptr, shr(mask_shift, msw)) +// bn_shift_ptr := add(bn_shift_ptr, 0x20) +// } +// } +// +// // as a result of creating the empty array we just have to operate on the words in the original bn. +// for(uint i=bn.val.length; i!=0; i-=0x20){ // for each word: +// assembly { +// msw := mload(msw_ptr) // get most significant word +// switch eq(i,0x20) // if i==32: +// case 1 { mask := 0 } // handles msword: no mask needed. +// default { mask := mload(add(msw_ptr,0x20)) } // else get mask (next word) +// msw := shl(bits, msw) // left shift current msw by 'bits' +// mask := shr(mask_shift, mask) // right shift next significant word by mask_shift +// mstore(bn_shift_ptr, or(msw,mask)) // store OR'd mask and shifted bits in-place +// msw_ptr := add(msw_ptr, 0x20) +// bn_shift_ptr := add(bn_shift_ptr, 0x20) +// } +// } +// +// r.val = bn_shift; +// } +// // ***************** END PRIVATE HELPER FUNCTIONS ****************** +//} diff --git a/contracts/utils/MemoryBigInt.sol b/contracts/utils/MemoryBigInt.sol new file mode 100644 index 0000000..b966620 --- /dev/null +++ b/contracts/utils/MemoryBigInt.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import {MemoryStack} from "./MemoryStack.sol"; +import "hardhat/console.sol"; + +library MemoryBigInt { + using MemoryStack for *; + + struct Heap { + uint256 field; + MemoryStack.Stack stack; + MemoryStack.Stack stack2x; + MemoryStack.Stack stack3x96; + } + + struct BigInt { + MemoryStack.StackValue data; + } + + function initHeap(uint256 field_) internal pure returns (Heap memory) { + return + Heap({ + field: field_, + stack: MemoryStack.init(field_), + stack2x: MemoryStack.init(2 * field_), + stack3x96: MemoryStack.init(3 * field_ + 96) + }); + } + + function initBigInt( + Heap memory heap, + bytes memory data_ + ) internal view returns (BigInt memory bigInt_) { + return _initBigInt(heap, data_); + } + + // function destruct(Heap memory heap, BigInt memory bigInt_) internal pure { + // storage_.stack.pop(bigInt_.val); + // } + + // + // function add(Storage memory storage_, bytes memory a_, bytes memory b_) internal pure returns (bytes memory r_) { + // + // } + // + // function mul(Storage memory storage_, bytes memory a_, bytes memory b_) internal pure returns (bytes memory r_) { + // + // } + + function _initBigInt( + Heap memory heap, + bytes memory data_ + ) private view returns (BigInt memory r_) { + r_ = BigInt(heap.stack.push0()); + + uint256 rPointer_ = heap.stack.toPointer(r_.data); + uint256 field_ = heap.field; + + assembly { + let dataSize_ := mload(data_) + let offset_ := sub(field_, dataSize_) + + mstore(rPointer_, field_) + + let success_ := staticcall( + 450, + 0x4, + add(data_, 0x20), + dataSize_, + add(add(rPointer_, 0x20), offset_), + dataSize_ + ) + if iszero(success_) { + revert(0, 0) + } + } + } +} diff --git a/contracts/utils/MemoryStack.sol b/contracts/utils/MemoryStack.sol new file mode 100644 index 0000000..6e0b247 --- /dev/null +++ b/contracts/utils/MemoryStack.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import {Vector} from "@solarity/solidity-lib/libs/data-structures/memory/Vector.sol"; + +library MemoryStack { + using Vector for Vector.UintVector; + + struct Stack { + Vector.UintVector stack; + uint256 stackSize; + uint256 elementSize; + } + + struct StackValue { + bytes value; + } + + function init(uint256 elementSize_) internal pure returns (Stack memory) { + require(elementSize_ % 32 == 0, "MS: invalid element size"); + + return Stack({stack: Vector.newUint(), stackSize: 0, elementSize: elementSize_}); + } + + function push0(Stack memory stack) internal view returns (StackValue memory value_) { + return push(stack, ""); + } + + function push( + Stack memory stack, + bytes memory data_ + ) internal view returns (StackValue memory value_) { + /// @dev It's an invariant that can only be violated by direct memory manipulation + require(stack.stackSize <= stack.stack.length(), "MS: stack overflow"); + + uint256 elementSize_ = stack.elementSize; + require(data_.length <= elementSize_, "MS: element size exceeded"); + + uint256 pointer_; + + if (stack.stackSize == stack.stack.length()) { + assembly { + pointer_ := mload(0x40) + + /// @dev 32 bytes for metadata, 32 bytes for length, and 32 bytes for data + mstore(0x40, add(pointer_, add(elementSize_, 0x40))) + + pointer_ := add(pointer_, 0x20) + } + + stack.stack.push(pointer_); + } else { + pointer_ = stack.stack.at(stack.stackSize); + } + + uint256 index_ = stack.stackSize; + + assembly { + mstore(sub(pointer_, 0x20), index_) + + let dataSize_ := add(mload(data_), 0x20) + + let success_ := staticcall(gas(), 0x4, data_, dataSize_, pointer_, dataSize_) + if iszero(success_) { + revert(0, 0) + } + + mstore(value_, pointer_) + } + + ++stack.stackSize; + } + + function pop(Stack memory stack, StackValue memory value_) internal pure { + (uint256 index_, uint256 pointer_) = _checkValue(stack, value_); + + if (index_ + 1 < stack.stackSize) { + uint256 lastIndex_ = stack.stackSize - 1; + uint256 lastPointer_ = stack.stack.at(lastIndex_); + + assembly { + mstore(sub(lastPointer_, 0x20), index_) + } + + stack.stack.set(index_, lastPointer_); + stack.stack.set(lastIndex_, pointer_); + } + + uint256 slots_ = stack.elementSize / 32 + 1; + + assembly { + for { + let i := 0 + } lt(i, mul(slots_, 0x20)) { + i := add(i, 0x20) + } { + mstore(add(pointer_, i), 0x0) + } + } + + --stack.stackSize; + } + + function toData( + Stack memory stack, + StackValue memory value_ + ) internal view returns (bytes memory data_) { + _checkValue(stack, value_); + + assembly { + data_ := mload(0x40) + + let dataSize_ := add(mload(value_), 0x20) + + let success_ := staticcall(gas(), 0x4, mload(value_), dataSize_, data_, dataSize_) + if iszero(success_) { + revert(0, 0) + } + + mstore(0x40, add(data_, dataSize_)) + } + } + + function toPointer( + Stack memory stack, + StackValue memory value_ + ) internal pure returns (uint256 pointer_) { + (, pointer_) = _checkValue(stack, value_); + } + + function _checkValue( + Stack memory stack, + StackValue memory value_ + ) internal pure returns (uint256 index_, uint256 pointer_) { + assembly { + index_ := mload(sub(mload(value_), 0x20)) + pointer_ := mload(value_) + } + + require(index_ < stack.stackSize, "MS: invalid index"); + require(stack.stack.at(index_) == pointer_, "MS: invalid value"); + } +} diff --git a/test/utils/Stack.test.ts b/test/utils/Stack.test.ts new file mode 100644 index 0000000..5ed097e --- /dev/null +++ b/test/utils/Stack.test.ts @@ -0,0 +1,27 @@ +import { ethers } from "hardhat"; + +import { StackMock } from "@ethers-v6"; + +import { getPoseidon, Reverter } from "@/test/helpers/"; + +describe.only("Stack", () => { + const reverter = new Reverter(); + + let stack: StackMock; + + before("setup", async () => { + const Stack = await ethers.getContractFactory("StackMock"); + + stack = await Stack.deploy(); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe("stack", () => { + it("stack", async () => { + console.log(await stack.mock()); + }); + }); +}); From e2e6a249ceac32293381042d251fec72550c69fc Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Mon, 7 Oct 2024 20:40:11 +0300 Subject: [PATCH 02/45] fix --- contracts/utils/MemoryBigInt.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/MemoryBigInt.sol b/contracts/utils/MemoryBigInt.sol index b966620..ec457f5 100644 --- a/contracts/utils/MemoryBigInt.sol +++ b/contracts/utils/MemoryBigInt.sol @@ -64,7 +64,7 @@ library MemoryBigInt { mstore(rPointer_, field_) let success_ := staticcall( - 450, + gas(), 0x4, add(data_, 0x20), dataSize_, From 21d11286d1e153ddb9ebb40cfdfa0ed986b3f448 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Wed, 9 Oct 2024 17:17:57 +0300 Subject: [PATCH 03/45] basic impl --- contracts/mock/utils/StackMock.sol | 15 +- contracts/utils/BigNumbers.sol | 2 +- contracts/utils/MemoryBigInt.sol | 79 ------ contracts/utils/MemoryStack.sol | 8 +- contracts/utils/MemoryUint.sol | 408 +++++++++++++++++++++++++++++ 5 files changed, 418 insertions(+), 94 deletions(-) delete mode 100644 contracts/utils/MemoryBigInt.sol create mode 100644 contracts/utils/MemoryUint.sol diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol index 77c730d..a8d5bd5 100644 --- a/contracts/mock/utils/StackMock.sol +++ b/contracts/mock/utils/StackMock.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import "../../utils/MemoryStack.sol"; -import "../../utils/MemoryBigInt.sol"; +import {MemoryStack} from "../../utils/MemoryStack.sol"; +import {MemoryUint} from "../../utils/MemoryUint.sol"; import "hardhat/console.sol"; contract StackMock { using MemoryStack for MemoryStack.Stack; - using MemoryBigInt for *; + using MemoryUint for *; //// let t: bigint; //// let u: bigint; @@ -48,11 +48,12 @@ contract StackMock { //// let z1 = modmul(u, u, p); //// z1 = modmul(z1, u, p); //// - function mock() external view returns (MemoryBigInt.BigInt memory) { - MemoryBigInt.Heap memory heap_ = MemoryBigInt.initHeap(64); + function mock() external view returns (MemoryUint.Uint512 memory) { + MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); - MemoryBigInt.BigInt memory a_ = heap_.initBigInt(hex"1337"); + MemoryUint.Uint512 memory a_ = mem_.newUint512(hex"10"); + MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"20"); - return a_; + return MemoryUint.modadd(mem_, a_, b_); } } diff --git a/contracts/utils/BigNumbers.sol b/contracts/utils/BigNumbers.sol index 4410753..0e38c55 100644 --- a/contracts/utils/BigNumbers.sol +++ b/contracts/utils/BigNumbers.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; - +// //// Definition here allows both the lib and inheriting contracts to use BigNumber directly. // struct BigNumber { // bytes val; diff --git a/contracts/utils/MemoryBigInt.sol b/contracts/utils/MemoryBigInt.sol deleted file mode 100644 index ec457f5..0000000 --- a/contracts/utils/MemoryBigInt.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; - -import {MemoryStack} from "./MemoryStack.sol"; -import "hardhat/console.sol"; - -library MemoryBigInt { - using MemoryStack for *; - - struct Heap { - uint256 field; - MemoryStack.Stack stack; - MemoryStack.Stack stack2x; - MemoryStack.Stack stack3x96; - } - - struct BigInt { - MemoryStack.StackValue data; - } - - function initHeap(uint256 field_) internal pure returns (Heap memory) { - return - Heap({ - field: field_, - stack: MemoryStack.init(field_), - stack2x: MemoryStack.init(2 * field_), - stack3x96: MemoryStack.init(3 * field_ + 96) - }); - } - - function initBigInt( - Heap memory heap, - bytes memory data_ - ) internal view returns (BigInt memory bigInt_) { - return _initBigInt(heap, data_); - } - - // function destruct(Heap memory heap, BigInt memory bigInt_) internal pure { - // storage_.stack.pop(bigInt_.val); - // } - - // - // function add(Storage memory storage_, bytes memory a_, bytes memory b_) internal pure returns (bytes memory r_) { - // - // } - // - // function mul(Storage memory storage_, bytes memory a_, bytes memory b_) internal pure returns (bytes memory r_) { - // - // } - - function _initBigInt( - Heap memory heap, - bytes memory data_ - ) private view returns (BigInt memory r_) { - r_ = BigInt(heap.stack.push0()); - - uint256 rPointer_ = heap.stack.toPointer(r_.data); - uint256 field_ = heap.field; - - assembly { - let dataSize_ := mload(data_) - let offset_ := sub(field_, dataSize_) - - mstore(rPointer_, field_) - - let success_ := staticcall( - gas(), - 0x4, - add(data_, 0x20), - dataSize_, - add(add(rPointer_, 0x20), offset_), - dataSize_ - ) - if iszero(success_) { - revert(0, 0) - } - } - } -} diff --git a/contracts/utils/MemoryStack.sol b/contracts/utils/MemoryStack.sol index 6e0b247..ad75bef 100644 --- a/contracts/utils/MemoryStack.sol +++ b/contracts/utils/MemoryStack.sol @@ -72,6 +72,7 @@ library MemoryStack { } function pop(Stack memory stack, StackValue memory value_) internal pure { + /// FIXME: still can point to another value (uint256 index_, uint256 pointer_) = _checkValue(stack, value_); if (index_ + 1 < stack.stackSize) { @@ -121,13 +122,6 @@ library MemoryStack { } } - function toPointer( - Stack memory stack, - StackValue memory value_ - ) internal pure returns (uint256 pointer_) { - (, pointer_) = _checkValue(stack, value_); - } - function _checkValue( Stack memory stack, StackValue memory value_ diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol new file mode 100644 index 0000000..0da5ab3 --- /dev/null +++ b/contracts/utils/MemoryUint.sol @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import {MemoryStack} from "./MemoryStack.sol"; + +library MemoryUint { + using MemoryStack for *; + + struct SharedMemory { + MemoryStack.Stack stack; + MemoryStack.Stack overflowStack; + MemoryStack.Stack callStack; + } + + struct Uint512 { + MemoryStack.StackValue data; + } + + function newUint512SharedMemory() internal view returns (SharedMemory memory mem_) { + mem_.stack = MemoryStack.init(64); + mem_.overflowStack = MemoryStack.init(160); + mem_.callStack = MemoryStack.init(1024); + + return mem_; + } + + function newUint512( + SharedMemory memory mem_, + bytes memory data_ + ) internal view returns (Uint512 memory u512_) { + require(data_.length <= 64, "MBI: data is too large"); + _checkMemory(mem_, 64); + + /// TODO: Can we pass here mem as a pointer? + return Uint512(_initUint(mem_, data_)); + } + + function destruct(SharedMemory memory mem_, Uint512 memory u512_) internal view { + _destruct(mem_, u512_.data, _StackType._UINT); + } + + enum _StackType { + _UINT, + _OVERFLOW_UINT, + _CALL + } + + function _checkMemory(SharedMemory memory mem_, uint256 bytesCount_) private view { + require(mem_.stack.elementSize == bytesCount_, "MBI: invalid memory"); + } + + function _new( + SharedMemory memory mem_, + _StackType stackType_ + ) private view returns (MemoryStack.StackValue memory value_) { + if (stackType_ == _StackType._UINT) { + return mem_.stack.push0(); + } + + if (stackType_ == _StackType._OVERFLOW_UINT) { + return mem_.overflowStack.push0(); + } + + return mem_.callStack.push0(); + } + + function _destruct( + SharedMemory memory mem_, + MemoryStack.StackValue memory value_, + _StackType stackType_ + ) private view { + if (stackType_ == _StackType._UINT) { + mem_.stack.pop(value_); + return; + } + + if (stackType_ == _StackType._OVERFLOW_UINT) { + mem_.overflowStack.pop(value_); + return; + } + + mem_.callStack.pop(value_); + } + + function _memSize( + SharedMemory memory mem_, + _StackType stackType_ + ) private view returns (uint256) { + if (stackType_ == _StackType._UINT) { + return mem_.stack.elementSize; + } + + if (stackType_ == _StackType._OVERFLOW_UINT) { + return mem_.overflowStack.elementSize; + } + + return mem_.callStack.elementSize; + } + + function _newUint( + SharedMemory memory mem_, + uint256 value_ + ) private view returns (MemoryStack.StackValue memory r_) { + uint256 overflowMemSize_ = _memSize(mem_, _StackType._OVERFLOW_UINT); + + r_ = _new(mem_, _StackType._OVERFLOW_UINT); + + assembly { + mstore(mload(r_), overflowMemSize_) + mstore(add(mload(r_), overflowMemSize_), value_) + } + } + + function modadd( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory b_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + MemoryStack.StackValue memory sum_ = _add(mem_, a_.data, b_.data); + + r_ = Uint512(_cut(mem_, sum_)); + + _destruct(mem_, sum_, _StackType._OVERFLOW_UINT); + } + + function modadd( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory b_, + Uint512 memory m_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + MemoryStack.StackValue memory sum_ = _add(mem_, a_.data, b_.data); + + r_ = Uint512(_mod(mem_, sum_, m_.data)); + + _destruct(mem_, sum_, _StackType._OVERFLOW_UINT); + } + + function mod( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory m_ + ) private view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + return Uint512(_mod(mem_, a_.data, m_.data)); + } + + function modexp( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory e_, + Uint512 memory m_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + return Uint512(_modexp(mem_, a_.data, e_.data, m_.data)); + } + + function _mod( + SharedMemory memory mem_, + MemoryStack.StackValue memory a_, + MemoryStack.StackValue memory m_ + ) private view returns (MemoryStack.StackValue memory r_) { + MemoryStack.StackValue memory one_ = _newUint(mem_, 1); + + r_ = _modexp(mem_, a_, one_, m_); + + _destruct(mem_, one_, _StackType._OVERFLOW_UINT); + } + + function cmp( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory b_ + ) internal view returns (int) { + _checkMemory(mem_, 64); + + return _cmp(mem_, a_.data, b_.data); + } + + function _cmp( + SharedMemory memory mem_, + MemoryStack.StackValue memory a_, + MemoryStack.StackValue memory b_ + ) internal view returns (int256) { + uint256 memSize_ = _memSize(mem_, _StackType._UINT); + + uint256 aPointer_; + uint256 bPointer_; + + assembly { + aPointer_ := add(mload(a_), 0x20) + bPointer_ := add(mload(b_), 0x20) + } + + for (uint i = 0; i < memSize_; i += 32) { + uint256 aWord_; + uint256 bWord_; + + assembly { + aWord_ := mload(add(aPointer_, i)) + bWord_ := mload(add(bPointer_, i)) + } + + if (aWord_ > bWord_) { + return 1; + } + + if (bWord_ > aWord_) { + return -1; + } + } + + return 0; + } + + function _cut( + SharedMemory memory mem_, + MemoryStack.StackValue memory a_ + ) private view returns (MemoryStack.StackValue memory r_) { + r_ = _new(mem_, _StackType._UINT); + + uint256 memSize_ = _memSize(mem_, _StackType._UINT); + uint256 overflowMemSize_ = _memSize(mem_, _StackType._OVERFLOW_UINT); + + assembly { + mstore(mload(r_), memSize_) + + let offset_ := add(sub(overflowMemSize_, memSize_), 0x20) + + if iszero( + staticcall( + gas(), + 0x4, + add(mload(a_), offset_), + memSize_, + add(mload(r_), 0x20), + memSize_ + ) + ) { + revert(0, 0) + } + } + } + + function _add( + SharedMemory memory mem_, + MemoryStack.StackValue memory a_, + MemoryStack.StackValue memory b_ + ) private view returns (MemoryStack.StackValue memory r_) { + r_ = _new(mem_, _StackType._OVERFLOW_UINT); + + uint256 memSize_ = _memSize(mem_, _StackType._UINT); + uint256 overflowMemSize_ = _memSize(mem_, _StackType._OVERFLOW_UINT); + + assembly { + mstore(mload(r_), overflowMemSize_) + + let aPtr_ := add(mload(a_), memSize_) + let bPtr_ := add(mload(b_), memSize_) + let rPtr_ := add(mload(r_), overflowMemSize_) + + let carry_ := 0 + + for { + let i := memSize_ + } eq(iszero(i), 0) { + i := sub(i, 0x20) + } { + let aWord_ := mload(aPtr_) + let bWord_ := mload(bPtr_) + + let rWord_ := add(add(aWord_, bWord_), carry_) + + carry_ := and( + eq(gt(rWord_, aWord_), 0), + or(eq(iszero(carry_), 0), eq(iszero(bWord_), 0)) + ) + + mstore(rPtr_, rWord_) + + aPtr_ := sub(aPtr_, 0x20) + bPtr_ := sub(bPtr_, 0x20) + rPtr_ := sub(rPtr_, 0x20) + } + + mstore(rPtr_, carry_) + } + } + + function _modexp( + SharedMemory memory mem_, + MemoryStack.StackValue memory a_, + MemoryStack.StackValue memory e_, + MemoryStack.StackValue memory m_ + ) private view returns (MemoryStack.StackValue memory r_) { + r_ = _new(mem_, _StackType._OVERFLOW_UINT); + uint256 overflowMemSize_ = _memSize(mem_, _StackType._OVERFLOW_UINT); + + MemoryStack.StackValue memory call_ = _new(mem_, _StackType._CALL); + + assembly { + mstore(mload(call_), mload(mload(a_))) + mstore(add(mload(call_), 0x20), mload(mload(e_))) + mstore(add(mload(call_), 0x40), mload(mload(m_))) + + let offset_ := 0x60 + + { + let aSize_ := mload(mload(a_)) + + if iszero( + staticcall( + gas(), + 0x4, + add(mload(a_), 0x20), + aSize_, + add(mload(call_), offset_), + aSize_ + ) + ) { + revert(0, 0) + } + + offset_ := add(offset_, aSize_) + } + + { + let eSize_ := mload(mload(e_)) + + if iszero( + staticcall( + gas(), + 0x4, + add(mload(e_), 0x20), + eSize_, + add(mload(call_), offset_), + eSize_ + ) + ) { + revert(0, 0) + } + + offset_ := add(offset_, eSize_) + } + + let mSize_ := mload(mload(m_)) + + if iszero( + staticcall( + gas(), + 0x4, + add(mload(m_), 0x20), + mSize_, + add(mload(call_), offset_), + mSize_ + ) + ) { + revert(0, 0) + } + + offset_ := add(offset_, mSize_) + + mstore(mload(r_), overflowMemSize_) + + if iszero( + staticcall(gas(), 0x5, mload(call_), offset_, add(mload(r_), 0x20), mSize_) + ) { + revert(0, 0) + } + } + + _destruct(mem_, call_, _StackType._CALL); + } + + function _initUint( + SharedMemory memory mem_, + bytes memory data_ + ) private view returns (MemoryStack.StackValue memory r_) { + r_ = _new(mem_, _StackType._UINT); + + uint256 uSize_ = _memSize(mem_, _StackType._UINT); + + assembly { + let dataSize_ := mload(data_) + let offset_ := sub(uSize_, dataSize_) + + mstore(mload(r_), uSize_) + + let success_ := staticcall( + gas(), + 0x4, + add(data_, 0x20), + dataSize_, + add(add(mload(r_), 0x20), offset_), + dataSize_ + ) + if iszero(success_) { + revert(0, 0) + } + } + } +} From 877112018d8d44cffced1ecb3a3b172b5488fdd1 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Wed, 9 Oct 2024 18:07:59 +0300 Subject: [PATCH 04/45] adjustments --- contracts/utils/MemoryUint.sol | 103 ++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index 0da5ab3..ae325f9 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -97,6 +97,21 @@ library MemoryUint { return mem_.callStack.elementSize; } + function _valueType( + SharedMemory memory mem_, + MemoryStack.StackValue memory value_ + ) private view returns (_StackType) { + if (value_.value.length == mem_.stack.elementSize) { + return _StackType._UINT; + } + + if (value_.value.length == mem_.overflowStack.elementSize) { + return _StackType._OVERFLOW_UINT; + } + + return _StackType._CALL; + } + function _newUint( SharedMemory memory mem_, uint256 value_ @@ -190,12 +205,12 @@ library MemoryUint { ) internal view returns (int256) { uint256 memSize_ = _memSize(mem_, _StackType._UINT); - uint256 aPointer_; - uint256 bPointer_; + uint256 aPtr_; + uint256 bPtr_; assembly { - aPointer_ := add(mload(a_), 0x20) - bPointer_ := add(mload(b_), 0x20) + aPtr_ := add(mload(a_), 0x20) + bPtr_ := add(mload(b_), 0x20) } for (uint i = 0; i < memSize_; i += 32) { @@ -203,8 +218,8 @@ library MemoryUint { uint256 bWord_; assembly { - aWord_ := mload(add(aPointer_, i)) - bWord_ := mload(add(bPointer_, i)) + aWord_ := mload(add(aPtr_, i)) + bWord_ := mload(add(bPtr_, i)) } if (aWord_ > bWord_) { @@ -299,57 +314,49 @@ library MemoryUint { MemoryStack.StackValue memory e_, MemoryStack.StackValue memory m_ ) private view returns (MemoryStack.StackValue memory r_) { - r_ = _new(mem_, _StackType._OVERFLOW_UINT); - uint256 overflowMemSize_ = _memSize(mem_, _StackType._OVERFLOW_UINT); - + r_ = _new(mem_, _valueType(mem_, m_)); MemoryStack.StackValue memory call_ = _new(mem_, _StackType._CALL); assembly { - mstore(mload(call_), mload(mload(a_))) - mstore(add(mload(call_), 0x20), mload(mload(e_))) - mstore(add(mload(call_), 0x40), mload(mload(m_))) + let aSize_ := mload(mload(a_)) + let eSize_ := mload(mload(e_)) + let mSize_ := mload(mload(m_)) + + mstore(mload(call_), aSize_) + mstore(add(mload(call_), 0x20), eSize_) + mstore(add(mload(call_), 0x40), mSize_) let offset_ := 0x60 - { - let aSize_ := mload(mload(a_)) - - if iszero( - staticcall( - gas(), - 0x4, - add(mload(a_), 0x20), - aSize_, - add(mload(call_), offset_), - aSize_ - ) - ) { - revert(0, 0) - } - - offset_ := add(offset_, aSize_) + if iszero( + staticcall( + gas(), + 0x4, + add(mload(a_), 0x20), + aSize_, + add(mload(call_), offset_), + aSize_ + ) + ) { + revert(0, 0) } - { - let eSize_ := mload(mload(e_)) - - if iszero( - staticcall( - gas(), - 0x4, - add(mload(e_), 0x20), - eSize_, - add(mload(call_), offset_), - eSize_ - ) - ) { - revert(0, 0) - } - - offset_ := add(offset_, eSize_) + offset_ := add(offset_, aSize_) + + if iszero( + staticcall( + gas(), + 0x4, + add(mload(e_), 0x20), + eSize_, + add(mload(call_), offset_), + eSize_ + ) + ) { + revert(0, 0) } - let mSize_ := mload(mload(m_)) + offset_ := add(offset_, eSize_) if iszero( staticcall( @@ -366,7 +373,7 @@ library MemoryUint { offset_ := add(offset_, mSize_) - mstore(mload(r_), overflowMemSize_) + mstore(mload(r_), mSize_) if iszero( staticcall(gas(), 0x5, mload(call_), offset_, add(mload(r_), 0x20), mSize_) From cadc8baf4c5122de0c95e6f3f50c6466c5a1e679 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Wed, 9 Oct 2024 18:10:45 +0300 Subject: [PATCH 05/45] fix --- contracts/mock/utils/StackMock.sol | 2 +- contracts/utils/MemoryUint.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol index a8d5bd5..e475df9 100644 --- a/contracts/mock/utils/StackMock.sol +++ b/contracts/mock/utils/StackMock.sol @@ -54,6 +54,6 @@ contract StackMock { MemoryUint.Uint512 memory a_ = mem_.newUint512(hex"10"); MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"20"); - return MemoryUint.modadd(mem_, a_, b_); + return MemoryUint.add(mem_, a_, b_); } } diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index ae325f9..487ce25 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -126,7 +126,7 @@ library MemoryUint { } } - function modadd( + function add( SharedMemory memory mem_, Uint512 memory a_, Uint512 memory b_ From 7f3b3bdbf89df04ce79cfaa1390fa5349cca2426 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Thu, 10 Oct 2024 16:36:55 +0300 Subject: [PATCH 06/45] refactored & sub --- contracts/mock/utils/StackMock.sol | 7 +- contracts/utils/MemoryUint.sol | 186 ++++++++++++++++++++--------- 2 files changed, 136 insertions(+), 57 deletions(-) diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol index e475df9..586743f 100644 --- a/contracts/mock/utils/StackMock.sol +++ b/contracts/mock/utils/StackMock.sol @@ -51,9 +51,10 @@ contract StackMock { function mock() external view returns (MemoryUint.Uint512 memory) { MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); - MemoryUint.Uint512 memory a_ = mem_.newUint512(hex"10"); - MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"20"); + MemoryUint.Uint512 memory a_ = mem_.newUint512(hex"05"); + MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"07"); + MemoryUint.Uint512 memory m_ = mem_.newUint512(hex"0A"); - return MemoryUint.add(mem_, a_, b_); + return MemoryUint.modsub(mem_, a_, b_, m_); } } diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index 487ce25..caebea1 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; +import "./MemoryStack.sol"; import {MemoryStack} from "./MemoryStack.sol"; library MemoryUint { @@ -8,7 +9,7 @@ library MemoryUint { struct SharedMemory { MemoryStack.Stack stack; - MemoryStack.Stack overflowStack; + MemoryStack.Stack extStack; MemoryStack.Stack callStack; } @@ -18,7 +19,7 @@ library MemoryUint { function newUint512SharedMemory() internal view returns (SharedMemory memory mem_) { mem_.stack = MemoryStack.init(64); - mem_.overflowStack = MemoryStack.init(160); + mem_.extStack = MemoryStack.init(160); mem_.callStack = MemoryStack.init(1024); return mem_; @@ -41,7 +42,7 @@ library MemoryUint { enum _StackType { _UINT, - _OVERFLOW_UINT, + _EXT_UINT, _CALL } @@ -57,8 +58,8 @@ library MemoryUint { return mem_.stack.push0(); } - if (stackType_ == _StackType._OVERFLOW_UINT) { - return mem_.overflowStack.push0(); + if (stackType_ == _StackType._EXT_UINT) { + return mem_.extStack.push0(); } return mem_.callStack.push0(); @@ -74,8 +75,8 @@ library MemoryUint { return; } - if (stackType_ == _StackType._OVERFLOW_UINT) { - mem_.overflowStack.pop(value_); + if (stackType_ == _StackType._EXT_UINT) { + mem_.extStack.pop(value_); return; } @@ -90,8 +91,8 @@ library MemoryUint { return mem_.stack.elementSize; } - if (stackType_ == _StackType._OVERFLOW_UINT) { - return mem_.overflowStack.elementSize; + if (stackType_ == _StackType._EXT_UINT) { + return mem_.extStack.elementSize; } return mem_.callStack.elementSize; @@ -105,8 +106,8 @@ library MemoryUint { return _StackType._UINT; } - if (value_.value.length == mem_.overflowStack.elementSize) { - return _StackType._OVERFLOW_UINT; + if (value_.value.length == mem_.extStack.elementSize) { + return _StackType._EXT_UINT; } return _StackType._CALL; @@ -116,13 +117,13 @@ library MemoryUint { SharedMemory memory mem_, uint256 value_ ) private view returns (MemoryStack.StackValue memory r_) { - uint256 overflowMemSize_ = _memSize(mem_, _StackType._OVERFLOW_UINT); + uint256 memSize_ = _memSize(mem_, _StackType._UINT); - r_ = _new(mem_, _StackType._OVERFLOW_UINT); + r_ = _new(mem_, _StackType._UINT); assembly { - mstore(mload(r_), overflowMemSize_) - mstore(add(mload(r_), overflowMemSize_), value_) + mstore(mload(r_), memSize_) + mstore(add(mload(r_), memSize_), value_) } } @@ -133,11 +134,46 @@ library MemoryUint { ) internal view returns (Uint512 memory r_) { _checkMemory(mem_, 64); - MemoryStack.StackValue memory sum_ = _add(mem_, a_.data, b_.data); + return Uint512(_add(mem_, a_.data, b_.data)); + } + + function sub( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory b_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + return Uint512(_sub(mem_, a_.data, b_.data)); + } + + function _extend( + SharedMemory memory mem_, + MemoryStack.StackValue memory value_ + ) private view returns (MemoryStack.StackValue memory valueExt_) { + valueExt_ = _new(mem_, _StackType._EXT_UINT); + + uint256 memSize_ = _memSize(mem_, _StackType._UINT); + uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); + + assembly { + mstore(mload(valueExt_), extMemSize_) - r_ = Uint512(_cut(mem_, sum_)); + let offset_ := sub(extMemSize_, memSize_) - _destruct(mem_, sum_, _StackType._OVERFLOW_UINT); + if iszero( + staticcall( + gas(), + 0x4, + add(mload(value_), 0x20), + memSize_, + add(add(mload(valueExt_), 0x20), offset_), + memSize_ + ) + ) { + revert(0, 0) + } + } } function modadd( @@ -148,11 +184,42 @@ library MemoryUint { ) internal view returns (Uint512 memory r_) { _checkMemory(mem_, 64); - MemoryStack.StackValue memory sum_ = _add(mem_, a_.data, b_.data); + MemoryStack.StackValue memory aExt_ = _extend(mem_, a_.data); + MemoryStack.StackValue memory bExt_ = _extend(mem_, b_.data); + + MemoryStack.StackValue memory sum_ = _add(mem_, aExt_, bExt_); r_ = Uint512(_mod(mem_, sum_, m_.data)); - _destruct(mem_, sum_, _StackType._OVERFLOW_UINT); + _destruct(mem_, aExt_, _StackType._EXT_UINT); + _destruct(mem_, bExt_, _StackType._EXT_UINT); + _destruct(mem_, sum_, _StackType._EXT_UINT); + } + + function modsub( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory b_, + Uint512 memory m_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + int cmp_ = _cmp(mem_, a_.data, b_.data); + + MemoryStack.StackValue memory diff_ = cmp_ >= 0 + ? _sub(mem_, a_.data, b_.data) + : _sub(mem_, b_.data, a_.data); + MemoryStack.StackValue memory modDiff_ = _mod(mem_, diff_, m_.data); + + _destruct(mem_, diff_, _StackType._UINT); + + if (cmp_ >= 0) { + return Uint512(modDiff_); + } + + r_ = Uint512(_sub(mem_, m_.data, modDiff_)); + + _destruct(mem_, modDiff_, _StackType._UINT); } function mod( @@ -185,7 +252,7 @@ library MemoryUint { r_ = _modexp(mem_, a_, one_, m_); - _destruct(mem_, one_, _StackType._OVERFLOW_UINT); + _destruct(mem_, one_, _StackType._UINT); } function cmp( @@ -198,12 +265,13 @@ library MemoryUint { return _cmp(mem_, a_.data, b_.data); } + /// @dev a_ and b_ are of the same size function _cmp( SharedMemory memory mem_, MemoryStack.StackValue memory a_, MemoryStack.StackValue memory b_ ) internal view returns (int256) { - uint256 memSize_ = _memSize(mem_, _StackType._UINT); + uint256 memSize_ = _memSize(mem_, _valueType(mem_, a_)); uint256 aPtr_; uint256 bPtr_; @@ -234,51 +302,64 @@ library MemoryUint { return 0; } - function _cut( + /// @dev a_, b_ and r_ are of the same size + function _add( SharedMemory memory mem_, - MemoryStack.StackValue memory a_ + MemoryStack.StackValue memory a_, + MemoryStack.StackValue memory b_ ) private view returns (MemoryStack.StackValue memory r_) { - r_ = _new(mem_, _StackType._UINT); - - uint256 memSize_ = _memSize(mem_, _StackType._UINT); - uint256 overflowMemSize_ = _memSize(mem_, _StackType._OVERFLOW_UINT); + r_ = _new(mem_, _valueType(mem_, a_)); assembly { + let memSize_ := mload(mload(a_)) + mstore(mload(r_), memSize_) - let offset_ := add(sub(overflowMemSize_, memSize_), 0x20) + let aPtr_ := add(mload(a_), memSize_) + let bPtr_ := add(mload(b_), memSize_) + let rPtr_ := add(mload(r_), memSize_) - if iszero( - staticcall( - gas(), - 0x4, - add(mload(a_), offset_), - memSize_, - add(mload(r_), 0x20), - memSize_ + let carry_ := 0 + + for { + let i := memSize_ + } eq(iszero(i), 0) { + i := sub(i, 0x20) + } { + let aWord_ := mload(aPtr_) + let bWord_ := mload(bPtr_) + let rWord_ := add(add(aWord_, bWord_), carry_) + + carry_ := and( + eq(gt(rWord_, aWord_), 0), + or(eq(iszero(carry_), 0), eq(iszero(bWord_), 0)) ) - ) { - revert(0, 0) + + mstore(rPtr_, rWord_) + + aPtr_ := sub(aPtr_, 0x20) + bPtr_ := sub(bPtr_, 0x20) + rPtr_ := sub(rPtr_, 0x20) } } } - function _add( + /// @dev a_, b_ and r_ are of the same size, a >= b + function _sub( SharedMemory memory mem_, MemoryStack.StackValue memory a_, MemoryStack.StackValue memory b_ ) private view returns (MemoryStack.StackValue memory r_) { - r_ = _new(mem_, _StackType._OVERFLOW_UINT); - - uint256 memSize_ = _memSize(mem_, _StackType._UINT); - uint256 overflowMemSize_ = _memSize(mem_, _StackType._OVERFLOW_UINT); + r_ = _new(mem_, _valueType(mem_, a_)); assembly { - mstore(mload(r_), overflowMemSize_) + let memSize_ := mload(mload(a_)) + + mstore(mload(r_), memSize_) let aPtr_ := add(mload(a_), memSize_) let bPtr_ := add(mload(b_), memSize_) - let rPtr_ := add(mload(r_), overflowMemSize_) + let rPtr_ := add(mload(r_), memSize_) let carry_ := 0 @@ -290,24 +371,21 @@ library MemoryUint { let aWord_ := mload(aPtr_) let bWord_ := mload(bPtr_) - let rWord_ := add(add(aWord_, bWord_), carry_) + mstore(rPtr_, sub(sub(aWord_, bWord_), carry_)) - carry_ := and( - eq(gt(rWord_, aWord_), 0), - or(eq(iszero(carry_), 0), eq(iszero(bWord_), 0)) + carry_ := or( + lt(aWord_, add(bWord_, carry_)), + and(eq(bWord_, sub(0, 1)), eq(carry_, 1)) ) - mstore(rPtr_, rWord_) - aPtr_ := sub(aPtr_, 0x20) bPtr_ := sub(bPtr_, 0x20) rPtr_ := sub(rPtr_, 0x20) } - - mstore(rPtr_, carry_) } } + /// @dev a_, e_, m_ can be of different sizes function _modexp( SharedMemory memory mem_, MemoryStack.StackValue memory a_, From 4713981f6476f9b1bdd4b34fce025af8eabe2c43 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Thu, 10 Oct 2024 18:43:21 +0300 Subject: [PATCH 07/45] added mul --- contracts/mock/utils/StackMock.sol | 2 +- contracts/utils/MemoryUint.sol | 145 ++++++++++++++++++++++++++++- 2 files changed, 145 insertions(+), 2 deletions(-) diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol index 586743f..f7033ff 100644 --- a/contracts/mock/utils/StackMock.sol +++ b/contracts/mock/utils/StackMock.sol @@ -55,6 +55,6 @@ contract StackMock { MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"07"); MemoryUint.Uint512 memory m_ = mem_.newUint512(hex"0A"); - return MemoryUint.modsub(mem_, a_, b_, m_); + return MemoryUint.modmul(mem_, a_, b_, m_); } } diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index caebea1..68e2b29 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import "./MemoryStack.sol"; import {MemoryStack} from "./MemoryStack.sol"; +import "hardhat/console.sol"; library MemoryUint { using MemoryStack for *; @@ -127,6 +127,27 @@ library MemoryUint { } } + function _newMaxUint( + SharedMemory memory mem_ + ) private view returns (MemoryStack.StackValue memory r_) { + uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); + + r_ = _new(mem_, _StackType._EXT_UINT); + + /// TODO: check + assembly { + mstore(mload(r_), extMemSize_) + + for { + let i := 0 + } lt(i, extMemSize_) { + i := add(i, 0x20) + } { + mstore(add(mload(r_), add(i, 0x20)), sub(0, 1)) + } + } + } + function add( SharedMemory memory mem_, Uint512 memory a_, @@ -176,6 +197,35 @@ library MemoryUint { } } + function _cut( + SharedMemory memory mem_, + MemoryStack.StackValue memory a_ + ) private view returns (MemoryStack.StackValue memory r_) { + r_ = _new(mem_, _StackType._UINT); + + uint256 memSize_ = _memSize(mem_, _StackType._UINT); + uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); + + assembly { + mstore(mload(r_), memSize_) + + let offset_ := add(sub(extMemSize_, memSize_), 0x20) + + if iszero( + staticcall( + gas(), + 0x4, + add(mload(a_), offset_), + memSize_, + add(mload(r_), 0x20), + memSize_ + ) + ) { + revert(0, 0) + } + } + } + function modadd( SharedMemory memory mem_, Uint512 memory a_, @@ -232,6 +282,99 @@ library MemoryUint { return Uint512(_mod(mem_, a_.data, m_.data)); } + function mul( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory b_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + MemoryStack.StackValue memory rExt_ = _mul(mem_, a_.data, b_.data); + + r_ = Uint512(_cut(mem_, rExt_)); + + _destruct(mem_, rExt_, _StackType._EXT_UINT); + } + + function modmul( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory b_, + Uint512 memory m_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + MemoryStack.StackValue memory rExt_ = _mul(mem_, a_.data, b_.data); + + r_ = Uint512(_mod(mem_, rExt_, m_.data)); + + _destruct(mem_, rExt_, _StackType._EXT_UINT); + } + + /// @dev a_, b_ are of the same size, r_ is extended + function _mul( + SharedMemory memory mem_, + MemoryStack.StackValue memory a_, + MemoryStack.StackValue memory b_ + ) private view returns (MemoryStack.StackValue memory r_) { + MemoryStack.StackValue memory aExt_ = _extend(mem_, a_); + MemoryStack.StackValue memory bExt_ = _extend(mem_, b_); + + MemoryStack.StackValue memory sumExt_ = _add(mem_, aExt_, bExt_); + + MemoryStack.StackValue memory two_ = _newUint(mem_, 2); + MemoryStack.StackValue memory maxModExt_ = _newMaxUint(mem_); + + MemoryStack.StackValue memory sqSumExt_ = _modexp(mem_, sumExt_, two_, maxModExt_); + + _destruct(mem_, sumExt_, _StackType._EXT_UINT); + + int256 cmp_ = _cmp(mem_, a_, b_); + + MemoryStack.StackValue memory diffExt_ = cmp_ >= 0 + ? _sub(mem_, aExt_, bExt_) + : _sub(mem_, bExt_, aExt_); + + MemoryStack.StackValue memory sqDiffExt_ = _modexp(mem_, diffExt_, two_, maxModExt_); + + _destruct(mem_, aExt_, _StackType._EXT_UINT); + _destruct(mem_, bExt_, _StackType._EXT_UINT); + _destruct(mem_, two_, _StackType._UINT); + _destruct(mem_, maxModExt_, _StackType._EXT_UINT); + _destruct(mem_, diffExt_, _StackType._EXT_UINT); + + r_ = _sub(mem_, sqSumExt_, sqDiffExt_); + + _destruct(mem_, sqSumExt_, _StackType._EXT_UINT); + _destruct(mem_, sqDiffExt_, _StackType._EXT_UINT); + + uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); + + assembly { + mstore(mload(r_), extMemSize_) + + let rPtr_ := add(mload(r_), extMemSize_) + + for { + let i := 0x20 + } lt(i, extMemSize_) { + i := add(i, 0x20) + } { + let rPtrNext_ := sub(rPtr_, 0x20) + let rWord_ := mload(rPtr_) + let rWordNext_ := mload(rPtrNext_) + + /// TODO: check + /// @dev (rWord_ >> 2) | ((rWordNext_ & 3) << 253) + mstore(rPtr_, or(shr(rWord_, 2), shl(and(rWordNext_, 3), 253))) + + rPtr_ := rPtrNext_ + } + + mstore(rPtr_, shr(mload(rPtr_), 2)) + } + } + function modexp( SharedMemory memory mem_, Uint512 memory a_, From da287d60b443ef69607f421bdd54a150821925c0 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 11 Oct 2024 12:44:41 +0300 Subject: [PATCH 08/45] added moddiv modinv --- contracts/mock/utils/StackMock.sol | 2 +- contracts/utils/MemoryUint.sol | 45 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol index f7033ff..26de5f2 100644 --- a/contracts/mock/utils/StackMock.sol +++ b/contracts/mock/utils/StackMock.sol @@ -55,6 +55,6 @@ contract StackMock { MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"07"); MemoryUint.Uint512 memory m_ = mem_.newUint512(hex"0A"); - return MemoryUint.modmul(mem_, a_, b_, m_); + return MemoryUint.moddiv(mem_, a_, b_, m_); } } diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index 68e2b29..d8d3018 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -311,6 +311,51 @@ library MemoryUint { _destruct(mem_, rExt_, _StackType._EXT_UINT); } + function _modinv( + SharedMemory memory mem_, + MemoryStack.StackValue memory a_, + MemoryStack.StackValue memory m_ + ) internal view returns (MemoryStack.StackValue memory r_) { + MemoryStack.StackValue memory two_ = _newUint(mem_, 2); + + require(_cmp(mem_, m_, two_) >= 0, "MBI: invalid modulus"); + + MemoryStack.StackValue memory exponent_ = _sub(mem_, m_, two_); + + _destruct(mem_, two_, _StackType._UINT); + + r_ = _modexp(mem_, a_, exponent_, m_); + + _destruct(mem_, exponent_, _StackType._UINT); + } + + function moddiv( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory b_, + Uint512 memory m_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + MemoryStack.StackValue memory bInv_ = _modinv(mem_, b_.data, m_.data); + MemoryStack.StackValue memory rExt_ = _mul(mem_, a_.data, bInv_); + + r_ = Uint512(_mod(mem_, rExt_, m_.data)); + + _destruct(mem_, rExt_, _StackType._EXT_UINT); + _destruct(mem_, bInv_, _StackType._UINT); + } + + function modinv( + SharedMemory memory mem_, + Uint512 memory a_, + Uint512 memory m_ + ) internal view returns (Uint512 memory r_) { + _checkMemory(mem_, 64); + + return Uint512(_modinv(mem_, a_.data, m_.data)); + } + /// @dev a_, b_ are of the same size, r_ is extended function _mul( SharedMemory memory mem_, From e134fb74b4598148f69fbef940293a194c3e0438 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 11 Oct 2024 12:52:05 +0300 Subject: [PATCH 09/45] typos --- contracts/utils/MemoryStack.sol | 2 +- contracts/utils/MemoryUint.sol | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/utils/MemoryStack.sol b/contracts/utils/MemoryStack.sol index ad75bef..599e391 100644 --- a/contracts/utils/MemoryStack.sol +++ b/contracts/utils/MemoryStack.sol @@ -42,7 +42,7 @@ library MemoryStack { assembly { pointer_ := mload(0x40) - /// @dev 32 bytes for metadata, 32 bytes for length, and 32 bytes for data + /// @dev 32 bytes for metadata, 32 bytes for length, and `elementSize_` bytes for data mstore(0x40, add(pointer_, add(elementSize_, 0x40))) pointer_ := add(pointer_, 0x20) diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index d8d3018..1182a88 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -29,7 +29,7 @@ library MemoryUint { SharedMemory memory mem_, bytes memory data_ ) internal view returns (Uint512 memory u512_) { - require(data_.length <= 64, "MBI: data is too large"); + require(data_.length <= 64, "MU: data is too large"); _checkMemory(mem_, 64); /// TODO: Can we pass here mem as a pointer? @@ -47,7 +47,7 @@ library MemoryUint { } function _checkMemory(SharedMemory memory mem_, uint256 bytesCount_) private view { - require(mem_.stack.elementSize == bytesCount_, "MBI: invalid memory"); + require(mem_.stack.elementSize == bytesCount_, "MU: invalid memory"); } function _new( @@ -318,7 +318,7 @@ library MemoryUint { ) internal view returns (MemoryStack.StackValue memory r_) { MemoryStack.StackValue memory two_ = _newUint(mem_, 2); - require(_cmp(mem_, m_, two_) >= 0, "MBI: invalid modulus"); + require(_cmp(mem_, m_, two_) >= 0, "MU: invalid modulus"); MemoryStack.StackValue memory exponent_ = _sub(mem_, m_, two_); From 1978065edd9ae03e87c5ed163ac4d858cd63a7e3 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Mon, 14 Oct 2024 13:05:05 +0300 Subject: [PATCH 10/45] fix --- contracts/mock/utils/StackMock.sol | 15 ++++++++++++++- contracts/utils/MemoryUint.sol | 17 ++++++----------- test/utils/Stack.test.ts | 5 ++++- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol index 26de5f2..0971299 100644 --- a/contracts/mock/utils/StackMock.sol +++ b/contracts/mock/utils/StackMock.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.4; import {MemoryStack} from "../../utils/MemoryStack.sol"; import {MemoryUint} from "../../utils/MemoryUint.sol"; -import "hardhat/console.sol"; contract StackMock { using MemoryStack for MemoryStack.Stack; @@ -57,4 +56,18 @@ contract StackMock { return MemoryUint.moddiv(mem_, a_, b_, m_); } + + function modmul( + bytes memory a_, + bytes memory b_, + bytes memory m_ + ) external view returns (MemoryUint.Uint512 memory) { + MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); + + MemoryUint.Uint512 memory a_ = mem_.newUint512(a_); + MemoryUint.Uint512 memory b_ = mem_.newUint512(b_); + MemoryUint.Uint512 memory m_ = mem_.newUint512(m_); + + return MemoryUint.modmul(mem_, a_, b_, m_); + } } diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index 1182a88..662a64a 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.4; import {MemoryStack} from "./MemoryStack.sol"; -import "hardhat/console.sol"; library MemoryUint { using MemoryStack for *; @@ -393,30 +392,26 @@ library MemoryUint { _destruct(mem_, sqSumExt_, _StackType._EXT_UINT); _destruct(mem_, sqDiffExt_, _StackType._EXT_UINT); - uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); - assembly { - mstore(mload(r_), extMemSize_) - - let rPtr_ := add(mload(r_), extMemSize_) + let rSize_ := mload(mload(r_)) + let rPtr_ := add(mload(r_), rSize_) for { let i := 0x20 - } lt(i, extMemSize_) { + } lt(i, rSize_) { i := add(i, 0x20) } { let rPtrNext_ := sub(rPtr_, 0x20) let rWord_ := mload(rPtr_) let rWordNext_ := mload(rPtrNext_) - /// TODO: check - /// @dev (rWord_ >> 2) | ((rWordNext_ & 3) << 253) - mstore(rPtr_, or(shr(rWord_, 2), shl(and(rWordNext_, 3), 253))) + /// @dev (rWord_ >> 2) | ((rWordNext_ & 3) << 254) + mstore(rPtr_, or(shr(2, rWord_), shl(254, and(3, rWordNext_)))) rPtr_ := rPtrNext_ } - mstore(rPtr_, shr(mload(rPtr_), 2)) + mstore(rPtr_, shr(2, mload(rPtr_))) } } diff --git a/test/utils/Stack.test.ts b/test/utils/Stack.test.ts index 5ed097e..414d44f 100644 --- a/test/utils/Stack.test.ts +++ b/test/utils/Stack.test.ts @@ -21,7 +21,10 @@ describe.only("Stack", () => { describe("stack", () => { it("stack", async () => { - console.log(await stack.mock()); + const y = BigInt("0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"); + const p = BigInt("0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"); + + console.log(await stack.modmul("0x" + y.toString(16), "0x" + y.toString(16), "0x" + p.toString(16))); }); }); }); From 4b8ef373fcb48659daa2886a5cee8b385aa7a827 Mon Sep 17 00:00:00 2001 From: joYyHack Date: Tue, 15 Oct 2024 18:10:20 +0300 Subject: [PATCH 11/45] bigint - optimized --- .vscode/settings.json | 1 + contracts/mock/utils/StackMock.sol | 130 +- .../PECDSASHA1Authenticator.sol | 28 +- .../PECDSASHA2Authenticator.sol | 335 +++++ .../PECDSASHA2NewAuthenticator.sol | 582 ++++++++ contracts/utils/BigInt.sol | 1309 +++++++++++++++++ contracts/utils/BigIntOpt.sol | 1200 +++++++++++++++ contracts/utils/MemoryUint.sol | 39 +- hardhat.config.ts | 32 +- package.json | 2 +- test/helpers/bigintHelper.ts | 233 +++ test/helpers/index.ts | 1 + .../PECDSAAuthenticator.test.ts | 110 ++ test/utils/Stack.test.ts | 2 +- 14 files changed, 3908 insertions(+), 96 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 contracts/passport/authenticators/PECDSASHA2Authenticator.sol create mode 100644 contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol create mode 100644 contracts/utils/BigInt.sol create mode 100644 contracts/utils/BigIntOpt.sol create mode 100644 test/helpers/bigintHelper.ts create mode 100644 test/passport/authenticators/PECDSAAuthenticator.test.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol index 0971299..dce5d7c 100644 --- a/contracts/mock/utils/StackMock.sol +++ b/contracts/mock/utils/StackMock.sol @@ -1,73 +1,73 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; +// // SPDX-License-Identifier: MIT +// pragma solidity ^0.8.4; -import {MemoryStack} from "../../utils/MemoryStack.sol"; -import {MemoryUint} from "../../utils/MemoryUint.sol"; +// import {MemoryStack} from "../../utils/MemoryStack.sol"; +// import {MemoryUint} from "../../utils/MemoryUint.sol"; -contract StackMock { - using MemoryStack for MemoryStack.Stack; - using MemoryUint for *; +// contract StackMock { +// using MemoryStack for MemoryStack.Stack; +// using MemoryUint for *; - //// let t: bigint; - //// let u: bigint; - //// let v: bigint; - //// let w: bigint; - //// - //// if (isZeroCurve(x0, y0)) { - //// return zeroProj(); - //// } - //// - //// u = modmul(y0, z0, p); - //// u = modmul(u, 2n, p); - //// - //// v = modmul(u, x0, p); - //// v = modmul(v, y0, p); - //// v = modmul(v, 2n, p); - //// - //// x0 = modmul(x0, x0, p); - //// t = modmul(x0, BigInt(3), p); - //// - //// z0 = modmul(z0, z0, p); - //// z0 = modmul(z0, a, p); - //// t = (t + z0) % p; - //// - //// w = modmul(t, t, p); - //// x0 = modmul(2n, v, p); - //// w = (w + (p - x0)) % p; - //// - //// x0 = (v + (p - w)) % p; - //// x0 = modmul(t, x0, p); - //// y0 = modmul(y0, u, p); - //// y0 = modmul(y0, y0, p); - //// y0 = modmul(2n, y0, p); - //// let y1 = (x0 + (p - y0)) % p; - //// - //// let x1 = modmul(u, w, p); - //// - //// let z1 = modmul(u, u, p); - //// z1 = modmul(z1, u, p); - //// - function mock() external view returns (MemoryUint.Uint512 memory) { - MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); +// //// let t: bigint; +// //// let u: bigint; +// //// let v: bigint; +// //// let w: bigint; +// //// +// //// if (isZeroCurve(x0, y0)) { +// //// return zeroProj(); +// //// } +// //// +// //// u = modmul(y0, z0, p); +// //// u = modmul(u, 2n, p); +// //// +// //// v = modmul(u, x0, p); +// //// v = modmul(v, y0, p); +// //// v = modmul(v, 2n, p); +// //// +// //// x0 = modmul(x0, x0, p); +// //// t = modmul(x0, BigInt(3), p); +// //// +// //// z0 = modmul(z0, z0, p); +// //// z0 = modmul(z0, a, p); +// //// t = (t + z0) % p; +// //// +// //// w = modmul(t, t, p); +// //// x0 = modmul(2n, v, p); +// //// w = (w + (p - x0)) % p; +// //// +// //// x0 = (v + (p - w)) % p; +// //// x0 = modmul(t, x0, p); +// //// y0 = modmul(y0, u, p); +// //// y0 = modmul(y0, y0, p); +// //// y0 = modmul(2n, y0, p); +// //// let y1 = (x0 + (p - y0)) % p; +// //// +// //// let x1 = modmul(u, w, p); +// //// +// //// let z1 = modmul(u, u, p); +// //// z1 = modmul(z1, u, p); +// //// +// function mock() external view returns (MemoryUint.Uint512 memory) { +// MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); - MemoryUint.Uint512 memory a_ = mem_.newUint512(hex"05"); - MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"07"); - MemoryUint.Uint512 memory m_ = mem_.newUint512(hex"0A"); +// MemoryUint.Uint512 memory a_ = mem_.newUint512(hex"05"); +// MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"07"); +// MemoryUint.Uint512 memory m_ = mem_.newUint512(hex"0A"); - return MemoryUint.moddiv(mem_, a_, b_, m_); - } +// return MemoryUint.moddiv(mem_, a_, b_, m_); +// } - function modmul( - bytes memory a_, - bytes memory b_, - bytes memory m_ - ) external view returns (MemoryUint.Uint512 memory) { - MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); +// function modmul( +// bytes memory a_, +// bytes memory b_, +// bytes memory m_ +// ) external view returns (MemoryUint.Uint512 memory) { +// MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); - MemoryUint.Uint512 memory a_ = mem_.newUint512(a_); - MemoryUint.Uint512 memory b_ = mem_.newUint512(b_); - MemoryUint.Uint512 memory m_ = mem_.newUint512(m_); +// MemoryUint.Uint512 memory a_ = mem_.newUint512(a_); +// MemoryUint.Uint512 memory b_ = mem_.newUint512(b_); +// MemoryUint.Uint512 memory m_ = mem_.newUint512(m_); - return MemoryUint.modmul(mem_, a_, b_, m_); - } -} +// return MemoryUint.modmul(mem_, a_, b_, m_); +// } +// } diff --git a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol index 19fb5cf..221d258 100644 --- a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.16; import {SHA1} from "../../utils/SHA1.sol"; +import "hardhat/console.sol"; /** * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol @@ -31,9 +32,9 @@ contract PECDSASHA1Authenticator { uint256 y ) external pure returns (bool) { /// @dev accept s only from the lower part of the curve - if (r == 0 || r >= n || s == 0 || s > lowSmax) { - return false; - } + // if (r == 0 || r >= n || s == 0 || s > lowSmax) { + // return false; + // } if (!_isOnCurve(x, y)) { return false; @@ -47,18 +48,26 @@ contract PECDSASHA1Authenticator { uint256 y2; uint256 sInv = _inverseMod(s, n); + (x1, y1) = _multiplyScalar(gx, gy, mulmod(message, sInv, n)); (x2, y2) = _multiplyScalar(x, y, mulmod(r, sInv, n)); + uint256[3] memory P = _addAndReturnProjectivePoint(x1, y1, x2, y2); - if (P[2] == 0) { - return false; - } + console.logBytes32(bytes32(P[0])); + console.logBytes32(bytes32(P[1])); + console.logBytes32(bytes32(P[2])); + + // if (P[2] == 0) { + // return false; + // } - uint256 Px = _inverseMod(P[2], p); - Px = mulmod(P[0], mulmod(Px, Px, p), p); + // uint256 Px = _inverseMod(P[2], p); + // Px = mulmod(P[0], mulmod(Px, Px, p), p); - return Px % n == r; + // return Px % n == r; + + return true; } /** @@ -81,7 +90,6 @@ contract PECDSASHA1Authenticator { while (r2 != 0) { q = r1 / r2; - unchecked { (t1, t2, r1, r2) = (t2, t1 - int256(q) * t2, r2, r1 - q * r2); } diff --git a/contracts/passport/authenticators/PECDSASHA2Authenticator.sol b/contracts/passport/authenticators/PECDSASHA2Authenticator.sol new file mode 100644 index 0000000..5da599d --- /dev/null +++ b/contracts/passport/authenticators/PECDSASHA2Authenticator.sol @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +import "hardhat/console.sol"; +import "../../utils/BigInt.sol"; +import "../../utils/BigIntOpt.sol"; + +/** + * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol + */ +contract PECDSASHA2Authenticator { + using BigInts for *; + using BigIntsOpt for *; + + BigInt zero = BigInts.zero(); + BigInt one = BigInts.one(); + BigInt two = BigInts.two(); + + BigIntOpt zeroOpt = BigIntsOpt.zero(); + BigIntOpt oneOpt = BigIntsOpt.one(); + BigIntOpt twoOpt = BigIntsOpt.two(); + + // Set parameters for curve. - secp384r1 + BigInt a = hex"7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9".init(false); + BigInt b = hex"26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6".init(false); + BigInt gx = + hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" + .init(false); + BigInt gy = + hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" + .init(false); + BigInt p = hex"A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377".init(false); + BigInt n = + hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" + .init(false); + + BigInt lowSmax = + hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" + .init(false); + + BigIntOpt aOpt = + hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" + .initOpt(false); + BigIntOpt bOpt = + hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF" + .initOpt(false); + BigIntOpt gxOpt = + hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" + .initOpt(false); + BigIntOpt gyOpt = + hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" + .initOpt(false); + BigIntOpt pOpt = + hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" + .initOpt(false); + BigIntOpt nOpt = + hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" + .initOpt(false); + + BigIntOpt lowSmaxOpt = + hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" + .initOpt(false); + + // step1 + function authenticate( + bytes memory challange, + bytes memory r, + bytes memory s, + bytes memory x, + bytes memory y + ) + external + view + returns ( + // bytes memory x0, + // bytes memory Px + bool + ) + { + BigInt memory r_ = r.init(false); + + //require(!r_.isZero() && !r_.gte(n) && !s.init(false).isZero()); // && !s.init(false).gt(lowSmax)); + require(_isOnCurve(x.init(false), y.init(false)), "Sec384: Not on curve"); + + // BigInt memory Px_ = Px.init(false); + // BigInt memory P = _toProjectivePoint(x0.init(false)); + + // Px_ = BigInts.modmul(P, BigInts.modmul(Px_, Px_, p), p); + + // return Px_.mod(n).eq(r_); + + return true; + } + + /** + * @dev Check if a point in affine coordinates is on the curve. + */ + function _isOnCurve(BigInt memory x, BigInt memory y) internal view returns (bool) { + if (x.isZero() || x.eq(p) || y.isZero() || y.eq(p)) { + return false; + } + + BigInt memory LHS = BigInts.modmul(y, y, p); // y^2 + BigInt memory RHS = BigInts.modmul(BigInts.modmul(x, x, p), x, p); // x^3 + + if (!a.isZero()) { + RHS = RHS.add(BigInts.modmul(x, a, p)).mod(p); + } + + if (!b.isZero()) { + RHS = RHS.add(b).mod(p); // x^3 + a*x + b + } + + return LHS.eq(RHS); + } + + /** + * @dev Transform affine coordinates into projective coordinates. + */ + function _toProjectivePoint(BigInt memory x0) internal view returns (BigInt memory) { + BigInt memory P = zero.add(one).mod(p); // P[2] + + require(!P.isZero()); + + return BigInts.modmul(x0, P, p); // P[0] + //P[1] = BigInts.modmul(y0, P[2], p); + } + + function _multiplyScalarPartial( + bytes memory x0, + bytes memory y0, + bytes memory scalar + ) public view returns (BigInt memory x1, BigInt memory y1, BigInt memory z1) { + BigInt memory x0_ = x0.init(false); + BigInt memory y0_ = y0.init(false); + BigInt memory scalar_ = scalar.init(false); + + // if (scalar === 0n) { + // return zeroAffine(); + // } else if (scalar === 1n) { + // return { x: x0, y: y0 }; + // } else if (scalar === 2n) { + // return twice(x0, y0); + // } + + BigInt memory base2X = x0_; + BigInt memory base2Y = y0_; + BigInt memory base2Z = one; + z1 = one; + x1 = x0_; + y1 = y0_; + + if (scalar_.mod(two).eq(one)) { + x1 = zero; + y1 = zero; + } + + scalar_ = scalar_.shr(1); + + //uint i = 0; + //while (scalar_.gt(zero)) { + // 382 + for (uint i = 0; i < 5; i++) { + (base2X, base2Y, base2Z) = _twiceProj(base2X, base2Y, base2Z); + + if (scalar_.mod(two).eq(one)) { + (x1, y1, z1) = _addProj(base2X, base2Y, base2Z, x1, y1, z1); + } + + scalar_ = scalar_.shr(1); + } + + // console.logBytes(base2X.val); + // console.logBytes(base2Y.val); + // console.logBytes(base2Z.val); + console.logBytes(x1.val); + console.logBytes(y1.val); + console.logBytes(z1.val); + + bytes32 size; + + console.log("msize"); + //4.211.872 + //4044a0 + assembly { + size := msize() + } + + console.log(uint256(size)); + + console.log("================"); + } + + function _twiceProj( + BigInt memory x0, + BigInt memory y0, + BigInt memory z0 + ) internal view returns (BigInt memory x1, BigInt memory y1, BigInt memory z1) { + BigInt memory t; + BigInt memory u; + BigInt memory v; + BigInt memory w; + + // if (_isZeroCurve(x0, y0)) { + // return _zeroProj(); + // } + + u = BigInts.modmul(y0, z0, p); + u = BigInts.modmul(u, two, p); + + v = BigInts.modmul(u, x0, p); + v = BigInts.modmul(v, y0, p); + v = BigInts.modmul(v, two, p); + + x0 = BigInts.modmul(x0, x0, p); + t = BigInts.modmul(x0, 3.init(false), p); + + z0 = BigInts.modmul(z0, z0, p); + z0 = BigInts.modmul(z0, a, p); + + // //t = (t + z0) % p; + t = t.add(z0).mod(p); + + w = BigInts.modmul(t, t, p); + x0 = BigInts.modmul(two, v, p); + + // //w = (w + (p - x0)) % p; + w = w.add(p.sub(x0)).mod(p); + + // //x0 = (v + (p - w)) % p; + x0 = v.add(p.sub(w)).mod(p); + + x0 = BigInts.modmul(t, x0, p); + y0 = BigInts.modmul(y0, u, p); + y0 = BigInts.modmul(y0, y0, p); + y0 = BigInts.modmul(two, y0, p); + + // //y1 = (x0 + (p - y0)) % p; + y1 = x0.add(p.sub(y0)).mod(p); + + x1 = BigInts.modmul(u, w, p); + + z1 = BigInts.modmul(u, u, p); + z1 = BigInts.modmul(z1, u, p); + } + + //2,724,209 + function _addProj( + BigInt memory x0, + BigInt memory y0, + BigInt memory z0, + BigInt memory x1, + BigInt memory y1, + BigInt memory z1 + ) internal view returns (BigInt memory x2, BigInt memory y2, BigInt memory z2) { + BigInt memory t0; + BigInt memory t1; + BigInt memory u0; + BigInt memory u1; + + if (_isZeroCurve(x0, y0)) { + return (x1, y1, z1); + } else if (_isZeroCurve(x1, y1)) { + return (x0, y0, z0); + } + + t0 = BigInts.modmul(y0, z1, p); + t1 = BigInts.modmul(y1, z0, p); + + u0 = BigInts.modmul(x0, z1, p); + u1 = BigInts.modmul(x1, z0, p); + + if (u0.eq(u1)) { + if (t0.eq(t1)) { + return _twiceProj(x0, y0, z0); + } else { + return _zeroProj(); + } + } + + (x2, y2, z2) = _addProj2(BigInts.modmul(z0, z1, p), u0, u1, t1, t0); + } + + /** + * @dev Helper function that splits addProj to avoid too many local variables. + */ + function _addProj2( + BigInt memory v, + BigInt memory u0, + BigInt memory u1, + BigInt memory t1, + BigInt memory t0 + ) internal view returns (BigInt memory x2, BigInt memory y2, BigInt memory z2) { + BigInt memory u; + BigInt memory u2; + BigInt memory u3; + BigInt memory w; + BigInt memory t; + + t = t0.add(p.sub(t1)).mod(p); + u = u0.add(p.sub(u1)).mod(p); + u2 = BigInts.modmul(u, u, p); + + w = BigInts.modmul(t, t, p); + w = BigInts.modmul(w, v, p); + u1 = u1.add(u0).mod(p); + u1 = BigInts.modmul(u1, u2, p); + w = w.add(p.sub(u1)).mod(p); + + x2 = BigInts.modmul(u, w, p); + + u3 = BigInts.modmul(u2, u, p); + u0 = BigInts.modmul(u0, u2, p); + u0 = u0.add(p.sub(w)).mod(p); + + t = BigInts.modmul(t, u0, p); + t0 = BigInts.modmul(t0, u3, p); + + y2 = t.add(p.sub(t0)).mod(p); + + z2 = BigInts.modmul(u3, v, p); + } + + function _isZeroCurve(BigInt memory x, BigInt memory y) internal view returns (bool) { + return x.eq(zero) && y.eq(zero); + } + + function _zeroProj() internal view returns (BigInt memory, BigInt memory, BigInt memory) { + return (zero, one, zero); + } + + function _zeroAffine() internal view returns (BigInt memory, BigInt memory) { + return (zero, zero); + } +} diff --git a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol new file mode 100644 index 0000000..3c51e00 --- /dev/null +++ b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol @@ -0,0 +1,582 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +import "hardhat/console.sol"; +import {Uint512, SharedMemory, MemoryUint} from "../../utils/MemoryUint.sol"; +import {SHA1} from "../../utils/SHA1.sol"; + +/** + * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol + */ +contract PECDSASHA2NewAuthenticator { + using MemoryUint for *; + using SHA1 for bytes; + + // secp384r1 parameters + struct Secp384rParams { + Uint512 a; + Uint512 b; + Uint512 gx; + Uint512 gy; + Uint512 p; + Uint512 n; + Uint512 lowSmax; + } + + struct XYZ { + Uint512 x; + Uint512 y; + Uint512 z; + } + + struct UT { + Uint512 u0; + Uint512 u1; + Uint512 t0; + Uint512 t1; + } + + struct UWT { + Uint512 u; + Uint512 u2; + Uint512 u3; + Uint512 w; + Uint512 t; + } + + struct TUVW { + Uint512 t; + Uint512 u; + Uint512 v; + Uint512 w; + } + + /** + * @notice Checks active authentication of a passport. ECDSA active authentication is an ECDSA signature of + * raw SHA2 hash of challenge bytes. Usually brainpool256r1 elliptic curve is used. + */ + function authenticate( + bytes memory challenge, + bytes memory r, + bytes memory s, + bytes memory x, + bytes memory y + ) external view returns (bool) { + SharedMemory memory _shMem = MemoryUint.newUint512SharedMemory(); + Secp384rParams memory _params = Secp384rParams({ + a: _shMem.newUint512( + hex"7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9" + ), + b: _shMem.newUint512( + hex"26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6" + ), + gx: _shMem.newUint512( + hex"8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262" + ), + gy: _shMem.newUint512( + hex"547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997" + ), + p: _shMem.newUint512( + hex"A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377" + ), + n: _shMem.newUint512( + hex"A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7" + ), + lowSmax: _shMem.newUint512( + hex"54fdabedd0f754de1f3305484ec1c6b9371dfb11ea9310141009a40e8fb729bb" + ) + }); + + Uint512 memory _x = _shMem.newUint512(x); + Uint512 memory _y = _shMem.newUint512(y); + + /// @dev accept s only from the lower part of the curve + // if (r == 0 || r >= n || s == 0 || s > lowSmax) { + // return false; + // } + + if (!_isOnCurve(_shMem, _params, _x, _y)) { + return false; + } + + Uint512 memory message = _shMem.newUint512(abi.encodePacked(uint160(challenge.sha1()))); + + Uint512 memory _s = _shMem.newUint512(s); + + Uint512 memory temp = _shMem.moddiv(message, _s, _params.n); + (Uint512 memory x1, Uint512 memory y1) = _multiplyScalar( + _shMem, + _params, + _params.gx, + _params.gy, + temp + ); + _shMem.destruct(temp); + + console.logBytes(x1.data.value); + console.logBytes(y1.data.value); + + // Uint512 memory _r = _shMem.newUint512(r); + + // temp = _shMem.moddiv(_r, _s, _params.n); + // (Uint512 memory x2, Uint512 memory y2) = _multiplyScalar(_shMem, _params, _x, _y, temp); + // _shMem.destruct(temp); + + // _shMem.destruct(_s); + + // Uint512 memory x1 = _shMem.newUint512( + // hex"237544e26b27436fe2825685b0c8c479b5a9fba1424eed1bdb46662edf7357a7" + // ); + // Uint512 memory x2 = _shMem.newUint512( + // hex"09e5dd89d2c91b8e803a1582af8835ef03824a43cbcd4cb7320b1aa675706add" + // ); + // Uint512 memory y1 = _shMem.newUint512( + // hex"5c746bb1eaef6275433511fbc7afa832abd79e58d7b06fe63104696f957e47fc" + // ); + // Uint512 memory y2 = _shMem.newUint512( + // hex"8fd8e0c00ea0ca899cbd668e8de533e5cadb188a3d37a633b953501196194f39" + // ); + + // Uint512[3] memory P = _addAndReturnProjectivePoint(_shMem, _params, x1, y1, x2, y2); + + // _shMem.destruct(x1); + // _shMem.destruct(x2); + // _shMem.destruct(y1); + // _shMem.destruct(y2); + + // Uint512 memory temp = _shMem.zero(); + // if (_shMem.cmp(P[2], temp) == 0) { + // return false; + // } + // _shMem.destruct(temp); + + // temp = _shMem.moddiv(P[2], P[2], _params.p); + // Uint512 memory Px = _shMem.modmul(P[0], temp, _params.p); + // _shMem.destruct(temp); + + // temp = _shMem.mod(Px, _params.n); + + // return _shMem.cmp(temp, _r) == 0; + } + + /** + * @dev Multiply an elliptic curve point by a scalar. + */ + function _multiplyScalar( + SharedMemory memory shMem, + Secp384rParams memory params, + Uint512 memory x0, + Uint512 memory y0, + Uint512 memory scalar + ) internal view returns (Uint512 memory x1, Uint512 memory y1) { + { + Uint512 memory zero = shMem.zero(); + Uint512 memory one = shMem.one(); + + if (shMem.cmp(scalar, zero) == 0) { + return _zeroAffine(shMem); + } else if (shMem.cmp(scalar, one) == 0) { + return (x0, y0); + } else { + Uint512 memory two = shMem.two(); + int256 res = shMem.cmp(scalar, two); + shMem.destruct(two); + + if (res == 0) { + return _twice(shMem, params, x0, y0); + } + } + } + + // Uint512 memory temp = shMem.mod(scalar, two); + // if (shMem.cmp(temp, zero) == 0) { + // x1 = shMem.zero(); + // y1 = shMem.zero(); + // } + + // shMem.destruct(temp); + + // scalar = scalar >> 1; + // while (scalar > 0) { + //(base2X, base2Y, base2Z) = _twiceProj(shMem, params, XYZ(base2X, base2Y, base2Z)); + + //Uint512 memory temp = shMem.mod(scalar, two); + //if (shMem.cmp(temp, one) == 0) { + //(x1, y1, z1) = _addProj(shMem, params, XYZ(base2X, base2Y, base2Z), XYZ(x1, y1, z1)); + //} + // scalar = scalar >> 1; + // } + + uint256 lowBits_; + + assembly { + lowBits_ := mload(add(mload(mload(scalar)), 0x40)) + } + + lowBits_ = lowBits_ >> 1; + + XYZ memory xyzBase = XYZ( + shMem.newUint512(x0.data.value), + shMem.newUint512(y0.data.value), + shMem.one() + ); + XYZ memory xyz1 = XYZ( + shMem.newUint512(x0.data.value), + shMem.newUint512(y0.data.value), + shMem.one() + ); + for (uint i = 0; i < 10; i++) { + //while (lowBits_ > 0) { + XYZ memory xyzBaseTemp; + xyzBaseTemp = _twiceProj(shMem, params, xyzBase); + + shMem.destruct(xyzBase.x); + shMem.destruct(xyzBase.y); + shMem.destruct(xyzBase.z); + + xyzBase = xyzBaseTemp; + + if (lowBits_ & 1 == 1) { + XYZ memory xyz1Temp; + xyz1Temp = _addProj(shMem, params, xyzBase, xyz1); + + shMem.destruct(xyz1.x); + shMem.destruct(xyz1.y); + shMem.destruct(xyz1.z); + + xyz1 = xyz1Temp; + } + + lowBits_ = lowBits_ >> 1; + } + + // shMem.destruct(zero); + // shMem.destruct(one); + + return _toAffinePoint(shMem, params, xyz1); + } + + /** + * @dev Double an elliptic curve point in projective coordinates. See + * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates + */ + function _twiceProj( + SharedMemory memory shMem, + Secp384rParams memory params, + XYZ memory xyz0 + ) internal view returns (XYZ memory xyz) { + TUVW memory tuvw; + + if (_isZeroCurve(shMem, xyz0.x, xyz0.y)) { + return _zeroProj(shMem); + } + + Uint512 memory two = shMem.two(); + Uint512 memory three = shMem.three(); + + tuvw.u = shMem.modmul(xyz0.y, xyz0.z, params.p); + tuvw.u = shMem.modmul(tuvw.u, two, params.p); + + tuvw.v = shMem.modmul(tuvw.u, xyz0.x, params.p); + tuvw.v = shMem.modmul(tuvw.v, xyz0.y, params.p); + tuvw.v = shMem.modmul(tuvw.v, two, params.p); + + xyz0.x = shMem.modmul(xyz0.x, xyz0.x, params.p); + + tuvw.t = shMem.modmul(xyz0.x, three, params.p); + + xyz0.z = shMem.modmul(xyz0.z, xyz0.z, params.p); + xyz0.z = shMem.modmul(xyz0.z, params.a, params.p); + + tuvw.t = shMem.modadd(tuvw.t, xyz0.z, params.p); + + tuvw.w = shMem.modmul(tuvw.t, tuvw.t, params.p); + + xyz0.x = shMem.modmul(two, tuvw.v, params.p); + + Uint512 memory temp = shMem.sub(params.p, xyz0.x); + tuvw.w = shMem.modadd(tuvw.w, temp, params.p); + + shMem.destruct(temp); + + temp = shMem.sub(params.p, tuvw.w); + xyz0.x = shMem.modadd(tuvw.v, temp, params.p); + + shMem.destruct(temp); + + xyz0.x = shMem.modmul(tuvw.t, xyz0.x, params.p); + + xyz0.y = shMem.modmul(xyz0.y, tuvw.u, params.p); + xyz0.y = shMem.modmul(xyz0.y, xyz0.y, params.p); + xyz0.y = shMem.modmul(two, xyz0.y, params.p); + + temp = shMem.sub(params.p, xyz0.y); + xyz.y = shMem.modadd(xyz0.x, temp, params.p); + + shMem.destruct(temp); + + xyz.x = shMem.modmul(tuvw.u, tuvw.w, params.p); + + xyz.z = shMem.modmul(tuvw.u, tuvw.u, params.p); + xyz.z = shMem.modmul(xyz.z, tuvw.u, params.p); + + shMem.destruct(tuvw.t); + shMem.destruct(tuvw.u); + shMem.destruct(tuvw.v); + shMem.destruct(tuvw.w); + } + + /** + * @dev Add two elliptic curve points in projective coordinates. See + * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates + */ + function _addProj( + SharedMemory memory shMem, + Secp384rParams memory params, + XYZ memory xyz0, + XYZ memory xyz1 + ) internal view returns (XYZ memory xyz) { + if (_isZeroCurve(shMem, xyz0.x, xyz0.y)) { + return XYZ(xyz1.x, xyz1.y, xyz1.z); + } else if (_isZeroCurve(shMem, xyz1.x, xyz1.y)) { + return XYZ(xyz0.x, xyz0.y, xyz0.z); + } + + Uint512 memory t0 = shMem.modmul(xyz0.y, xyz1.z, params.p); + Uint512 memory t1 = shMem.modmul(xyz1.y, xyz0.z, params.p); + + Uint512 memory u0 = shMem.modmul(xyz0.x, xyz1.z, params.p); + Uint512 memory u1 = shMem.modmul(xyz1.x, xyz0.z, params.p); + + if (shMem.cmp(u0, u1) == 0) { + if (shMem.cmp(t0, t1) == 0) { + xyz = _twiceProj(shMem, params, xyz0); + } else { + xyz = _zeroProj(shMem); + } + } else { + Uint512 memory temp = shMem.modmul(xyz0.z, xyz1.z, params.p); + xyz = _addProj2(shMem, params, temp, UT(u0, u1, t0, t1)); + + shMem.destruct(temp); + } + + shMem.destruct(t0); + shMem.destruct(t1); + shMem.destruct(u0); + shMem.destruct(u1); + } + + /** + * @dev Helper function that splits addProj to avoid too many local variables. + */ + function _addProj2( + SharedMemory memory shMem, + Secp384rParams memory params, + Uint512 memory v, + UT memory ut + ) internal view returns (XYZ memory xyz) { + UWT memory uwt; + + Uint512 memory temp = shMem.sub(params.p, ut.t1); + uwt.t = shMem.modadd(ut.t0, temp, params.p); + + shMem.destruct(temp); + + temp = shMem.sub(params.p, ut.u1); + uwt.u = shMem.modadd(ut.u0, temp, params.p); + + shMem.destruct(temp); + + uwt.u2 = shMem.modmul(uwt.u, uwt.u, params.p); + + uwt.w = shMem.modmul(uwt.t, uwt.t, params.p); + uwt.w = shMem.modmul(uwt.w, v, params.p); + ut.u1 = shMem.modadd(ut.u1, ut.u0, params.p); + ut.u1 = shMem.modmul(ut.u1, uwt.u2, params.p); + + temp = shMem.sub(params.p, ut.u1); + uwt.w = shMem.modadd(uwt.w, temp, params.p); + + shMem.destruct(temp); + + xyz.x = shMem.modmul(uwt.u, uwt.w, params.p); + + uwt.u3 = shMem.modmul(uwt.u2, uwt.u, params.p); + ut.u0 = shMem.modmul(ut.u0, uwt.u2, params.p); + + temp = shMem.sub(params.p, uwt.w); + ut.u0 = shMem.modadd(ut.u0, temp, params.p); + + uwt.t = shMem.modmul(uwt.t, ut.u0, params.p); + ut.t0 = shMem.modmul(ut.t0, uwt.u3, params.p); + + temp = shMem.sub(params.p, ut.t0); + xyz.y = shMem.modadd(uwt.t, temp, params.p); + + xyz.z = shMem.modmul(uwt.u3, v, params.p); + } + + /** + * @dev Add two elliptic curve points in affine coordinates. + */ + function _add( + SharedMemory memory shMem, + Secp384rParams memory params, + Uint512 memory x0, + Uint512 memory y0, + Uint512 memory x1, + Uint512 memory y1 + ) internal view returns (Uint512 memory x, Uint512 memory y) { + Uint512 memory one = shMem.one(); + + XYZ memory xyz = _addProj(shMem, params, XYZ(x0, y0, one), XYZ(x1, y1, one)); + (x, y) = _toAffinePoint(shMem, params, xyz); + + shMem.destruct(one); + shMem.destruct(xyz.x); + shMem.destruct(xyz.y); + shMem.destruct(xyz.z); + } + + /** + * @dev Double an elliptic curve point in affine coordinates. + */ + function _twice( + SharedMemory memory shMem, + Secp384rParams memory params, + Uint512 memory x0, + Uint512 memory y0 + ) internal view returns (Uint512 memory x, Uint512 memory y) { + Uint512 memory one = shMem.one(); + + XYZ memory xyz = _twiceProj(shMem, params, XYZ(x0, y0, one)); + + (x, y) = _toAffinePoint(shMem, params, xyz); + + shMem.destruct(one); + shMem.destruct(xyz.x); + shMem.destruct(xyz.y); + shMem.destruct(xyz.z); + } + + /** + * @dev Add two points in affine coordinates and return projective point. + */ + function _addAndReturnProjectivePoint( + SharedMemory memory shMem, + Secp384rParams memory params, + Uint512 memory x1, + Uint512 memory y1, + Uint512 memory x2, + Uint512 memory y2 + ) internal view returns (Uint512[3] memory P) { + (Uint512 memory x, Uint512 memory y) = _add(shMem, params, x1, y1, x2, y2); + P = _toProjectivePoint(shMem, params, x, y); + + shMem.destruct(x); + shMem.destruct(y); + } + + /** + * @dev Transform from projective to affine coordinates. + */ + function _toAffinePoint( + SharedMemory memory shMem, + Secp384rParams memory params, + XYZ memory xyz + ) internal view returns (Uint512 memory x1, Uint512 memory y1) { + x1 = shMem.moddiv(xyz.x, xyz.z, params.p); + y1 = shMem.moddiv(xyz.y, xyz.z, params.p); + } + + /** + * @dev Check if a point in affine coordinates is on the curve. + */ + function _isOnCurve( + SharedMemory memory shMem, + Secp384rParams memory params, + Uint512 memory x, + Uint512 memory y + ) internal view returns (bool res) { + Uint512 memory zero = shMem.zero(); + if ( + shMem.cmp(x, zero) == 0 || + shMem.cmp(y, zero) == 0 || + shMem.cmp(x, params.p) == 0 || + shMem.cmp(y, params.p) == 0 + ) { + return false; + } + + Uint512 memory temp = shMem.modmul(x, x, params.p); + + Uint512 memory RHS = shMem.modmul(temp, x, params.p); // x^3 + Uint512 memory LHS = shMem.modmul(y, y, params.p); // y^2x + + shMem.destruct(temp); + + if (shMem.cmp(params.a, zero) != 0) { + temp = shMem.modmul(x, params.a, params.p); + RHS = shMem.modadd(RHS, temp, params.p); // x^3 + a*x + + shMem.destruct(temp); + } + if (shMem.cmp(params.b, zero) != 0) { + RHS = shMem.modadd(RHS, params.b, params.p); // x^3 + a*x + b + } + + res = shMem.cmp(LHS, RHS) == 0; + + shMem.destruct(zero); + shMem.destruct(LHS); + shMem.destruct(RHS); + } + + /** + * @dev Transform affine coordinates into projective coordinates. + */ + function _toProjectivePoint( + SharedMemory memory shMem, + Secp384rParams memory params, + Uint512 memory x0, + Uint512 memory y0 + ) internal view returns (Uint512[3] memory P) { + Uint512 memory zero = shMem.zero(); + Uint512 memory one = shMem.one(); + P[2] = shMem.modadd(zero, one, params.p); + P[0] = shMem.modmul(x0, P[2], params.p); + P[1] = shMem.modmul(y0, P[2], params.p); + } + + /** + * @dev Return the zero curve in projective coordinates. + */ + function _zeroProj(SharedMemory memory shMem) internal view returns (XYZ memory) { + return XYZ(shMem.zero(), shMem.one(), shMem.zero()); + } + + /** + * @dev Return the zero curve in affine coordinates. + */ + function _zeroAffine( + SharedMemory memory shMem + ) internal view returns (Uint512 memory x, Uint512 memory y) { + return (shMem.zero(), shMem.zero()); + } + + /** + * @dev Check if the curve is the zero curve. + */ + function _isZeroCurve( + SharedMemory memory shMem, + Uint512 memory x0, + Uint512 memory y0 + ) internal view returns (bool isZero) { + Uint512 memory zero = shMem.zero(); + bool res = shMem.cmp(x0, zero) == 0 && shMem.cmp(y0, zero) == 0; + + shMem.destruct(zero); + return res; + } +} diff --git a/contracts/utils/BigInt.sol b/contracts/utils/BigInt.sol new file mode 100644 index 0000000..24905ab --- /dev/null +++ b/contracts/utils/BigInt.sol @@ -0,0 +1,1309 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +import "hardhat/console.sol"; +// Definition here allows both the lib and inheriting contracts to use BigInt directly. +struct BigInt { + bytes val; + bool neg; + uint bitlen; +} + +/** + * @notice BigInts library for Solidity. + */ +library BigInts { + /// @notice the value for number 0 of a BigInt instance. + bytes constant ZERO = hex"0000000000000000000000000000000000000000000000000000000000000000"; + /// @notice the value for number 1 of a BigInt instance. + bytes constant ONE = hex"0000000000000000000000000000000000000000000000000000000000000001"; + /// @notice the value for number 2 of a BigInt instance. + bytes constant TWO = hex"0000000000000000000000000000000000000000000000000000000000000002"; + + // ***************** BEGIN EXPOSED MANAGEMENT FUNCTIONS ****************** + /** @notice verify a BN instance + * @dev checks if the BN is in the correct format. operations should only be carried out on + * verified BNs, so it is necessary to call this if your function takes an arbitrary BN + * as input. + * + * @param bn BigInt instance + */ + function verify( + BigInt memory bn + ) internal pure { + uint msword; + bytes memory val = bn.val; + assembly {msword := mload(add(val,0x20))} //get msword of result + if(msword==0) require(isZero(bn)); + else require((bn.val.length % 32 == 0) && (msword>>((bn.bitlen-1)%256)==1)); + } + + /** @notice initialize a BN instance + * @dev wrapper function for _init. initializes from bytes value. + * Allows passing bitLength of value. This is NOT verified in the internal function. Only use where bitlen is + * explicitly known; otherwise use the other init function. + * + * @param val BN value. may be of any size. + * @param neg neg whether the BN is +/- + * @param bitlen bit length of output. + * @return BigInt instance + */ + function init( + bytes memory val, + bool neg, + uint bitlen + ) internal view returns(BigInt memory){ + return _init(val, neg, bitlen); + } + + /** @notice initialize a BN instance + * @dev wrapper function for _init. initializes from bytes value. + * + * @param val BN value. may be of any size. + * @param neg neg whether the BN is +/- + * @return BigInt instance + */ + function init( + bytes memory val, + bool neg + ) internal view returns(BigInt memory){ + return _init(val, neg, 0); + } + + /** @notice initialize a BN instance + * @dev wrapper function for _init. initializes from uint value (converts to bytes); + * tf. resulting BN is in the range -2^256-1 ... 2^256-1. + * + * @param val uint value. + * @param neg neg whether the BN is +/- + * @return BigInt instance + */ + function init( + uint val, + bool neg + ) internal view returns(BigInt memory){ + return _init(abi.encodePacked(val), neg, 0); + } + // ***************** END EXPOSED MANAGEMENT FUNCTIONS ****************** + + + + + // ***************** BEGIN EXPOSED CORE CALCULATION FUNCTIONS ****************** + /** @notice BigInt addition: a + b. + * @dev add: Initially prepare BigInts for addition operation; internally calls actual addition/subtraction, + * depending on inputs. + * In order to do correct addition or subtraction we have to handle the sign. + * This function discovers the sign of the result based on the inputs, and calls the correct operation. + * + * @param a first BN + * @param b second BN + * @return r result - addition of a and b. + */ + function add( + BigInt memory a, + BigInt memory b + ) internal pure returns(BigInt memory r) { + if(a.bitlen==0 && b.bitlen==0) return zero(); + if(a.bitlen==0) return b; + if(b.bitlen==0) return a; + bytes memory val; + uint bitlen; + int compare = cmp(a,b,false); + + if(a.neg || b.neg){ + if(a.neg && b.neg){ + if(compare>=0) (val, bitlen) = _add(a.val,b.val,a.bitlen); + else (val, bitlen) = _add(b.val,a.val,b.bitlen); + r.neg = true; + } + else { + if(compare==1){ + (val, bitlen) = _sub(a.val,b.val); + r.neg = a.neg; + } + else if(compare==-1){ + (val, bitlen) = _sub(b.val,a.val); + r.neg = !a.neg; + } + else return zero();//one pos and one neg, and same value. + } + } + else{ + if(compare>=0){ // a>=b + (val, bitlen) = _add(a.val,b.val,a.bitlen); + } + else { + (val, bitlen) = _add(b.val,a.val,b.bitlen); + } + r.neg = false; + } + + r.val = val; + r.bitlen = (bitlen); + } + + /** @notice BigInt subtraction: a - b. + * @dev sub: Initially prepare BigInts for subtraction operation; internally calls actual addition/subtraction, + depending on inputs. + * In order to do correct addition or subtraction we have to handle the sign. + * This function discovers the sign of the result based on the inputs, and calls the correct operation. + * + * @param a first BN + * @param b second BN + * @return r result - subtraction of a and b. + */ + function sub( + BigInt memory a, + BigInt memory b + ) internal pure returns(BigInt memory r) { + if(a.bitlen==0 && b.bitlen==0) return zero(); + bytes memory val; + int compare; + uint bitlen; + compare = cmp(a,b,false); + if(a.neg || b.neg) { + if(a.neg && b.neg){ + if(compare == 1) { + (val,bitlen) = _sub(a.val,b.val); + r.neg = true; + } + else if(compare == -1) { + + (val,bitlen) = _sub(b.val,a.val); + r.neg = false; + } + else return zero(); + } + else { + if(compare >= 0) (val,bitlen) = _add(a.val,b.val,a.bitlen); + else (val,bitlen) = _add(b.val,a.val,b.bitlen); + + r.neg = (a.neg) ? true : false; + } + } + else { + if(compare == 1) { + (val,bitlen) = _sub(a.val,b.val); + r.neg = false; + } + else if(compare == -1) { + (val,bitlen) = _sub(b.val,a.val); + r.neg = true; + } + else return zero(); + } + + r.val = val; + r.bitlen = (bitlen); + } + + /** @notice BigInt multiplication: a * b. + * @dev mul: takes two BigInts and multiplys them. Order is irrelevant. + * multiplication achieved using modexp precompile: + * (a * b) = ((a + b)**2 - (a - b)**2) / 4 + * + * @param a first BN + * @param b second BN + * @return r result - multiplication of a and b. + */ + function mul( + BigInt memory a, + BigInt memory b + ) internal view returns(BigInt memory r){ + + BigInt memory lhs = add(a,b); + BigInt memory fst = modexp(lhs, two(), _powModulus(lhs, 2)); // (a+b)^2 + + // no need to do subtraction part of the equation if a == b; if so, it has no effect on final result. + if(!eq(a,b)) { + BigInt memory rhs = sub(a,b); + BigInt memory snd = modexp(rhs, two(), _powModulus(rhs, 2)); // (a-b)^2 + r = _shr(sub(fst, snd) , 2); // (a * b) = (((a + b)**2 - (a - b)**2) / 4 + } + else { + r = _shr(fst, 2); // a==b ? (((a + b)**2 / 4 + } + } + + /** @notice BigInt division verification: a * b. + * @dev div: takes three BigInts (a,b and result), and verifies that a/b == result. + * Performing BigInt division on-chain is a significantly expensive operation. As a result, + * we expose the ability to verify the result of a division operation, which is a constant time operation. + * (a/b = result) == (a = b * result) + * Integer division only; therefore: + * verify ((b*result) + (a % (b*result))) == a. + * eg. 17/7 == 2: + * verify (7*2) + (17 % (7*2)) == 17. + * The function returns a bool on successful verification. The require statements will ensure that false can never + * be returned, however inheriting contracts may also want to put this function inside a require statement. + * + * @param a first BigInt + * @param b second BigInt + * @param r result BigInt + * @return bool whether or not the operation was verified + */ + function divVerify( + BigInt memory a, + BigInt memory b, + BigInt memory r + ) internal view returns(bool) { + + // first do zero check. + // if ab. + * + * @param a BigInt + * @param b BigInt + * @param signed whether to consider sign of inputs + * @return int result + */ + function cmp( + BigInt memory a, + BigInt memory b, + bool signed + ) internal pure returns(int){ + int trigger = 1; + if(signed){ + if(a.neg && b.neg) trigger = -1; + else if(a.neg==false && b.neg==true) return 1; + else if(a.neg==true && b.neg==false) return -1; + } + + if(a.bitlen>b.bitlen) return trigger; // 1*trigger + if(b.bitlen>a.bitlen) return -1*trigger; + + uint a_ptr; + uint b_ptr; + uint a_word; + uint b_word; + + uint len = a.val.length; //bitlen is same so no need to check length. + + assembly{ + a_ptr := add(mload(a),0x20) + b_ptr := add(mload(b),0x20) + } + + for(uint i=0; ib_word) return trigger; // 1*trigger + if(b_word>a_word) return -1*trigger; + + } + + return 0; //same value. + } + + /** @notice BigInt equality + * @dev eq: returns true if a==b. sign always considered. + * + * @param a BigInt + * @param b BigInt + * @return boolean result + */ + function eq( + BigInt memory a, + BigInt memory b + ) internal pure returns(bool){ + int result = cmp(a, b, true); + return (result==0) ? true : false; + } + + /** @notice BigInt greater than + * @dev eq: returns true if a>b. sign always considered. + * + * @param a BigInt + * @param b BigInt + * @return boolean result + */ + function gt( + BigInt memory a, + BigInt memory b + ) internal pure returns(bool){ + int result = cmp(a, b, true); + return (result==1) ? true : false; + } + + /** @notice BigInt greater than or equal to + * @dev eq: returns true if a>=b. sign always considered. + * + * @param a BigInt + * @param b BigInt + * @return boolean result + */ + function gte( + BigInt memory a, + BigInt memory b + ) internal pure returns(bool){ + int result = cmp(a, b, true); + return (result==1 || result==0) ? true : false; + } + + /** @notice BigInt less than + * @dev eq: returns true if a= the bitlength of the value the result is always 0 + if(bits >= bn.bitlen) return BigInt(ZERO,false,0); + + // set bitlen initially as we will be potentially modifying 'bits' + bn.bitlen = bn.bitlen-(bits); + + // handle shifts greater than 256: + // if bits is greater than 256 we can simply remove any trailing words, by altering the BN length. + // we also update 'bits' so that it is now in the range 0..256. + assembly { + if or(gt(bits, 0x100), eq(bits, 0x100)) { + length := sub(length, mul(div(bits, 0x100), 0x20)) + mstore(mload(bn), length) + bits := mod(bits, 0x100) + } + + // if bits is multiple of 8 (byte size), we can simply use identity precompile for cheap memcopy. + // otherwise we shift each word, starting at the least signifcant word, one-by-one using the mask technique. + // TODO it is possible to do this without the last two operations, see SHL identity copy. + let bn_val_ptr := mload(bn) + switch eq(mod(bits, 8), 0) + case 1 { + let bytes_shift := div(bits, 8) + let in := mload(bn) + let inlength := mload(in) + let insize := add(inlength, 0x20) + let out := add(in, bytes_shift) + let outsize := sub(insize, bytes_shift) + let success := staticcall(450, 0x4, in, insize, out, insize) + mstore8(add(out, 0x1f), 0) // maintain our BN layout following identity call: + mstore(in, inlength) // set current length byte to 0, and reset old length. + } + default { + let mask + let lsw + let mask_shift := sub(0x100, bits) + let lsw_ptr := add(bn_val_ptr, length) + for { let i := length } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) + switch eq(i,0x20) // if i==32: + case 1 { mask := 0 } // - handles lsword: no mask needed. + default { mask := mload(sub(lsw_ptr,0x20)) } // - else get mask (previous word) + lsw := shr(bits, mload(lsw_ptr)) // right shift current by bits + mask := shl(mask_shift, mask) // left shift next significant word by mask_shift + mstore(lsw_ptr, or(lsw,mask)) // store OR'd mask and shifted bits in-place + lsw_ptr := sub(lsw_ptr, 0x20) // point to next bits. + } + } + + // The following removes the leading word containing all zeroes in the result should it exist, + // as well as updating lengths and pointers as necessary. + let msw_ptr := add(bn_val_ptr,0x20) + switch eq(mload(msw_ptr), 0) + case 1 { + mstore(msw_ptr, sub(mload(bn_val_ptr), 0x20)) // store new length in new position + mstore(bn, msw_ptr) // update pointer from bn + } + default {} + } + + + return bn; + } + + /** @notice left shift BigInt value + * @dev shr: left shift BigInt a by 'bits' bits. + ensures the value is not negative before calling the private function. + * @param a BigInt value to shift + * @param bits amount of bits to shift by + * @return result BigInt + */ + function shl( + BigInt memory a, + uint bits + ) internal view returns(BigInt memory){ + require(!a.neg); + return _shl(a, bits); + } + + /** @notice sha3 hash a BigInt. + * @dev hash: takes a BigInt and performs sha3 hash on it. + * we hash each BigInt WITHOUT it's first word - first word is a pointer to the start of the bytes value, + * and so is different for each struct. + * + * @param a BigInt + * @return h bytes32 hash. + */ + function hash( + BigInt memory a + ) internal pure returns(bytes32 h) { + //amount of words to hash = all words of the value and three extra words: neg, bitlen & value length. + assembly { + h := keccak256( add(a,0x20), add (mload(mload(a)), 0x60 ) ) + } + } + + /** @notice BigInt full zero check + * @dev isZero: checks if the BigInt is in the default zero format for BNs (ie. the result from zero()). + * + * @param a BigInt + * @return boolean result. + */ + function isZero( + BigInt memory a + ) internal pure returns(bool) { + return isZero(a.val) && a.val.length==0x20 && !a.neg && a.bitlen == 0; + } + + + /** @notice bytes zero check + * @dev isZero: checks if input bytes value resolves to zero. + * + * @param a bytes value + * @return boolean result. + */ + function isZero( + bytes memory a + ) internal pure returns(bool) { + uint msword; + uint msword_ptr; + assembly { + msword_ptr := add(a,0x20) + } + for(uint i=0; i 0) return false; + assembly { msword_ptr := add(msword_ptr, 0x20) } + } + return true; + + } + + /** @notice BigInt value bit length + * @dev bitLength: returns BigInt value bit length- ie. log2 (most significant bit of value) + * + * @param a BigInt + * @return uint bit length result. + */ + function bitLength( + BigInt memory a + ) internal pure returns(uint){ + return bitLength(a.val); + } + + /** @notice bytes bit length + * @dev bitLength: returns bytes bit length- ie. log2 (most significant bit of value) + * + * @param a bytes value + * @return r uint bit length result. + */ + function bitLength( + bytes memory a + ) internal pure returns(uint r){ + if(isZero(a)) return 0; + uint msword; + assembly { + msword := mload(add(a,0x20)) // get msword of input + } + r = bitLength(msword); // get bitlen of msword, add to size of remaining words. + assembly { + r := add(r, mul(sub(mload(a), 0x20) , 8)) // res += (val.length-32)*8; + } + } + + /** @notice uint bit length + @dev bitLength: get the bit length of a uint input - ie. log2 (most significant bit of 256 bit value (one EVM word)) + * credit: Tjaden Hess @ ethereum.stackexchange + * @param a uint value + * @return r uint bit length result. + */ + function bitLength( + uint a + ) internal pure returns (uint r){ + assembly { + switch eq(a, 0) + case 1 { + r := 0 + } + default { + let arg := a + a := sub(a,1) + a := or(a, div(a, 0x02)) + a := or(a, div(a, 0x04)) + a := or(a, div(a, 0x10)) + a := or(a, div(a, 0x100)) + a := or(a, div(a, 0x10000)) + a := or(a, div(a, 0x100000000)) + a := or(a, div(a, 0x10000000000000000)) + a := or(a, div(a, 0x100000000000000000000000000000000)) + a := add(a, 1) + let m := mload(0x40) + mstore(m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd) + mstore(add(m,0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe) + mstore(add(m,0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616) + mstore(add(m,0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff) + mstore(add(m,0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e) + mstore(add(m,0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707) + mstore(add(m,0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606) + mstore(add(m,0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100) + mstore(0x40, add(m, 0x100)) + let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff + let shift := 0x100000000000000000000000000000000000000000000000000000000000000 + let _a := div(mul(a, magic), shift) + r := div(mload(add(m,sub(255,_a))), shift) + r := add(r, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000))) + // where a is a power of two, result needs to be incremented. we use the power of two trick here: if(arg & arg-1 == 0) ++r; + if eq(and(arg, sub(arg, 1)), 0) { + r := add(r, 1) + } + } + } + } + + /** @notice BigInt zero value + @dev zero: returns zero encoded as a BigInt + * @return zero encoded as BigInt + */ + function zero( + ) internal pure returns(BigInt memory) { + return BigInt(ZERO, false, 0); + } + + /** @notice BigInt one value + @dev one: returns one encoded as a BigInt + * @return one encoded as BigInt + */ + function one( + ) internal pure returns(BigInt memory) { + return BigInt(ONE, false, 1); + } + + /** @notice BigInt two value + @dev two: returns two encoded as a BigInt + * @return two encoded as BigInt + */ + function two( + ) internal pure returns(BigInt memory) { + return BigInt(TWO, false, 2); + } + // ***************** END EXPOSED HELPER FUNCTIONS ****************** + + + + + + // ***************** START PRIVATE MANAGEMENT FUNCTIONS ****************** + /** @notice Create a new BigInt. + @dev init: overloading allows caller to obtionally pass bitlen where it is known - as it is cheaper to do off-chain and verify on-chain. + * we assert input is in data structure as defined above, and that bitlen, if passed, is correct. + * 'copy' parameter indicates whether or not to copy the contents of val to a new location in memory (for example where you pass + * the contents of another variable's value in) + * @param val bytes - bignum value. + * @param neg bool - sign of value + * @param bitlen uint - bit length of value + * @return r BigInt initialized value. + */ + function _init( + bytes memory val, + bool neg, + uint bitlen + ) private view returns(BigInt memory r){ + // use identity at location 0x4 for cheap memcpy. + // grab contents of val, load starting from memory end, update memory end pointer. + assembly { + let data := add(val, 0x20) + let length := mload(val) + let out + let freemem := mload(0x40) + switch eq(mod(length, 0x20), 0) // if(val.length % 32 == 0) + case 1 { + out := add(freemem, 0x20) // freememory location + length word + mstore(freemem, length) // set new length + } + default { + let offset := sub(0x20, mod(length, 0x20)) // offset: 32 - (length % 32) + out := add(add(freemem, offset), 0x20) // freememory location + offset + length word + mstore(freemem, add(length, offset)) // set new length + } + pop(staticcall(450, 0x4, data, length, out, length)) // copy into 'out' memory location + mstore(0x40, add(freemem, add(mload(freemem), 0x20))) // update the free memory pointer + + // handle leading zero words. assume freemem is pointer to bytes value + let bn_length := mload(freemem) + for { } eq ( eq(bn_length, 0x20), 0) { } { // for(; length!=32; length-=32) + switch eq(mload(add(freemem, 0x20)),0) // if(msword==0): + case 1 { freemem := add(freemem, 0x20) } // update length pointer + default { break } // else: loop termination. non-zero word found + bn_length := sub(bn_length,0x20) + } + mstore(freemem, bn_length) + + mstore(r, freemem) // store new bytes value in r + mstore(add(r, 0x20), neg) // store neg value in r + } + + r.bitlen = bitlen == 0 ? bitLength(r.val) : bitlen; + } + // ***************** END PRIVATE MANAGEMENT FUNCTIONS ****************** + + + + + + // ***************** START PRIVATE CORE CALCULATION FUNCTIONS ****************** + /** @notice takes two BigInt memory values and the bitlen of the max value, and adds them. + * @dev _add: This function is private and only callable from add: therefore the values may be of different sizes, + * in any order of size, and of different signs (handled in add). + * As values may be of different sizes, inputs are considered starting from the least significant + * words, working back. + * The function calculates the new bitlen (basically if bitlens are the same for max and min, + * max_bitlen++) and returns a new BigInt memory value. + * + * @param max bytes - biggest value (determined from add) + * @param min bytes - smallest value (determined from add) + * @param max_bitlen uint - bit length of max value. + * @return bytes result - max + min. + * @return uint - bit length of result. + */ + function _add( + bytes memory max, + bytes memory min, + uint max_bitlen + ) private pure returns (bytes memory, uint) { + bytes memory result; + assembly { + + let result_start := mload(0x40) // Get the highest available block of memory + let carry := 0 + let uint_max := sub(0,1) + + let max_ptr := add(max, mload(max)) + let min_ptr := add(min, mload(min)) // point to last word of each byte array. + + let result_ptr := add(add(result_start,0x20), mload(max)) // set result_ptr end. + + for { let i := mload(max) } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) + let max_val := mload(max_ptr) // get next word for 'max' + switch gt(i,sub(mload(max),mload(min))) // if(i>(max_length-min_length)). while + // 'min' words are still available. + case 1{ + let min_val := mload(min_ptr) // get next word for 'min' + mstore(result_ptr, add(add(max_val,min_val),carry)) // result_word = max_word+min_word+carry + switch gt(max_val, sub(uint_max,sub(min_val,carry))) // this switch block finds whether or + // not to set the carry bit for the + // next iteration. + case 1 { carry := 1 } + default { + switch and(eq(max_val,uint_max),or(gt(carry,0), gt(min_val,0))) + case 1 { carry := 1 } + default{ carry := 0 } + } + + min_ptr := sub(min_ptr,0x20) // point to next 'min' word + } + default{ // else: remainder after 'min' words are complete. + mstore(result_ptr, add(max_val,carry)) // result_word = max_word+carry + + switch and( eq(uint_max,max_val), eq(carry,1) ) // this switch block finds whether or + // not to set the carry bit for the + // next iteration. + case 1 { carry := 1 } + default { carry := 0 } + } + result_ptr := sub(result_ptr,0x20) // point to next 'result' word + max_ptr := sub(max_ptr,0x20) // point to next 'max' word + } + + switch eq(carry,0) + case 1{ result_start := add(result_start,0x20) } // if carry is 0, increment result_start, ie. + // length word for result is now one word + // position ahead. + default { mstore(result_ptr, 1) } // else if carry is 1, store 1; overflow has + // occured, so length word remains in the + // same position. + + result := result_start // point 'result' bytes value to the correct + // address in memory. + mstore(result,add(mload(max),mul(0x20,carry))) // store length of result. we are finished + // with the byte array. + + mstore(0x40, add(result,add(mload(result),0x20))) // Update freemem pointer to point to new + // end of memory. + + // we now calculate the result's bit length. + // with addition, if we assume that some a is at least equal to some b, then the resulting bit length will + // be a's bit length or (a's bit length)+1, depending on carry bit.this is cheaper than calling bitLength. + let msword := mload(add(result,0x20)) // get most significant word of result + // if(msword==1 || msword>>(max_bitlen % 256)==1): + if or( eq(msword, 1), eq(shr(mod(max_bitlen,256),msword),1) ) { + max_bitlen := add(max_bitlen, 1) // if msword's bit length is 1 greater + // than max_bitlen, OR overflow occured, + // new bitlen is max_bitlen+1. + } + } + + + return (result, max_bitlen); + } + + /** @notice takes two BigInt memory values and subtracts them. + * @dev _sub: This function is private and only callable from add: therefore the values may be of different sizes, + * in any order of size, and of different signs (handled in add). + * As values may be of different sizes, inputs are considered starting from the least significant words, + * working back. + * The function calculates the new bitlen (basically if bitlens are the same for max and min, + * max_bitlen++) and returns a new BigInt memory value. + * + * @param max bytes - biggest value (determined from add) + * @param min bytes - smallest value (determined from add) + * @return bytes result - max + min. + * @return uint - bit length of result. + */ + function _sub( + bytes memory max, + bytes memory min + ) internal pure returns (bytes memory, uint) { + bytes memory result; + uint carry = 0; + uint uint_max = type(uint256).max; + assembly { + + let result_start := mload(0x40) // Get the highest available block of + // memory + + let max_len := mload(max) + let min_len := mload(min) // load lengths of inputs + + let len_diff := sub(max_len,min_len) // get differences in lengths. + + let max_ptr := add(max, max_len) + let min_ptr := add(min, min_len) // go to end of arrays + let result_ptr := add(result_start, max_len) // point to least significant result + // word. + let memory_end := add(result_ptr,0x20) // save memory_end to update free memory + // pointer at the end. + + for { let i := max_len } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) + let max_val := mload(max_ptr) // get next word for 'max' + switch gt(i,len_diff) // if(i>(max_length-min_length)). while + // 'min' words are still available. + case 1{ + let min_val := mload(min_ptr) // get next word for 'min' + + mstore(result_ptr, sub(sub(max_val,min_val),carry)) // result_word = (max_word-min_word)-carry + + switch or(lt(max_val, add(min_val,carry)), + and(eq(min_val,uint_max), eq(carry,1))) // this switch block finds whether or + // not to set the carry bit for the next iteration. + case 1 { carry := 1 } + default { carry := 0 } + + min_ptr := sub(min_ptr,0x20) // point to next 'result' word + } + default { // else: remainder after 'min' words are complete. + + mstore(result_ptr, sub(max_val,carry)) // result_word = max_word-carry + + switch and( eq(max_val,0), eq(carry,1) ) // this switch block finds whether or + // not to set the carry bit for the + // next iteration. + case 1 { carry := 1 } + default { carry := 0 } + + } + result_ptr := sub(result_ptr,0x20) // point to next 'result' word + max_ptr := sub(max_ptr,0x20) // point to next 'max' word + } + + //the following code removes any leading words containing all zeroes in the result. + result_ptr := add(result_ptr,0x20) + + // for(result_ptr+=32;; result==0; result_ptr+=32) + for { } eq(mload(result_ptr), 0) { result_ptr := add(result_ptr,0x20) } { + result_start := add(result_start, 0x20) // push up the start pointer for the result + max_len := sub(max_len,0x20) // subtract a word (32 bytes) from the + // result length. + } + + result := result_start // point 'result' bytes value to + // the correct address in memory + + mstore(result,max_len) // store length of result. we + // are finished with the byte array. + + mstore(0x40, memory_end) // Update freemem pointer. + } + + uint new_bitlen = bitLength(result); // calculate the result's + // bit length. + + return (result, new_bitlen); + } + + /** @notice gets the modulus value necessary for calculating exponetiation. + * @dev _powModulus: we must pass the minimum modulus value which would return JUST the a^b part of the calculation + * in modexp. the rationale here is: + * if 'a' has n bits, then a^e has at most n*e bits. + * using this modulus in exponetiation will result in simply a^e. + * therefore the value may be many words long. + * This is done by: + * - storing total modulus byte length + * - storing first word of modulus with correct bit set + * - updating the free memory pointer to come after total length. + * + * @param a BigInt base + * @param e uint exponent + * @return BigInt modulus result + */ + function _powModulus( + BigInt memory a, + uint e + ) private pure returns(BigInt memory){ + bytes memory _modulus = ZERO; + uint mod_index; + + assembly { + mod_index := mul(mload(add(a, 0x40)), e) // a.bitlen * e is the max bitlength of result + let first_word_modulus := shl(mod(mod_index, 256), 1) // set bit in first modulus word. + mstore(_modulus, mul(add(div(mod_index,256),1),0x20)) // store length of modulus + mstore(add(_modulus,0x20), first_word_modulus) // set first modulus word + mstore(0x40, add(_modulus, add(mload(_modulus),0x20))) // update freemem pointer to be modulus index + // + length + } + + //create modulus BigInt memory for modexp function + return BigInt(_modulus, false, mod_index); + } + + /** @notice Modular Exponentiation: Takes bytes values for base, exp, mod and calls precompile for (base^exp)%^mod + * @dev modexp: Wrapper for built-in modexp (contract 0x5) as described here: + * https://github.com/ethereum/EIPs/pull/198 + * + * @param _b bytes base + * @param _e bytes base_inverse + * @param _m bytes exponent + * @param r bytes result. + */ + function _modexp( + bytes memory _b, + bytes memory _e, + bytes memory _m + ) private view returns(bytes memory r) { + assembly { + + let bl := mload(_b) + let el := mload(_e) + let ml := mload(_m) + + + let freemem := mload(0x40) // Free memory pointer is always stored at 0x40 + + + mstore(freemem, bl) // arg[0] = base.length @ +0 + + mstore(add(freemem,32), el) // arg[1] = exp.length @ +32 + + mstore(add(freemem,64), ml) // arg[2] = mod.length @ +64 + + // arg[3] = base.bits @ + 96 + // Use identity built-in (contract 0x4) as a cheap memcpy + let success := staticcall(450, 0x4, add(_b,32), bl, add(freemem,96), bl) + + // arg[4] = exp.bits @ +96+base.length + let size := add(96, bl) + success := staticcall(450, 0x4, add(_e,32), el, add(freemem,size), el) + + // arg[5] = mod.bits @ +96+base.length+exp.length + size := add(size,el) + success := staticcall(450, 0x4, add(_m,32), ml, add(freemem,size), ml) + + switch success case 0 { invalid() } //fail where we haven't enough gas to make the call + + // Total size of input = 96+base.length+exp.length+mod.length + size := add(size,ml) + // Invoke contract 0x5, put return value right after mod.length, @ +96 + success := staticcall(sub(gas(), 1350), 0x5, freemem, size, add(freemem, 0x60), ml) + + switch success case 0 { invalid() } //fail where we haven't enough gas to make the call + + let length := ml + let msword_ptr := add(freemem, 0x60) + + ///the following code removes any leading words containing all zeroes in the result. + for { } eq ( eq(length, 0x20), 0) { } { // for(; length!=32; length-=32) + switch eq(mload(msword_ptr),0) // if(msword==0): + case 1 { msword_ptr := add(msword_ptr, 0x20) } // update length pointer + default { break } // else: loop termination. non-zero word found + length := sub(length,0x20) + } + r := sub(msword_ptr,0x20) + mstore(r, length) + + // point to the location of the return value (length, bits) + //assuming mod length is multiple of 32, return value is already in the right format. + mstore(0x40, add(add(96, freemem),ml)) //deallocate freemem pointer + } + } + // ***************** END PRIVATE CORE CALCULATION FUNCTIONS ****************** + + + + + + // ***************** START PRIVATE HELPER FUNCTIONS ****************** + /** @notice left shift BigInt memory 'dividend' by 'value' bits. + * @param bn value to shift + * @param bits amount of bits to shift by + * @return r result + */ + function _shl( + BigInt memory bn, + uint bits + ) private view returns(BigInt memory r) { + if(bits==0 || bn.bitlen==0) return bn; + + // we start by creating an empty bytes array of the size of the output, based on 'bits'. + // for that we must get the amount of extra words needed for the output. + uint length = bn.val.length; + // position of bitlen in most significnat word + uint bit_position = ((bn.bitlen-1) % 256) + 1; + // total extra words. we check if the bits remainder will add one more word. + uint extra_words = (bits / 256) + ( (bits % 256) >= (256 - bit_position) ? 1 : 0); + // length of output + uint total_length = length + (extra_words * 0x20); + + r.bitlen = bn.bitlen+(bits); + r.neg = bn.neg; + bits %= 256; + + + bytes memory bn_shift; + uint bn_shift_ptr; + // the following efficiently creates an empty byte array of size 'total_length' + assembly { + let freemem_ptr := mload(0x40) // get pointer to free memory + mstore(freemem_ptr, total_length) // store bytes length + let mem_end := add(freemem_ptr, total_length) // end of memory + mstore(mem_end, 0) // store 0 at memory end + bn_shift := freemem_ptr // set pointer to bytes + bn_shift_ptr := add(bn_shift, 0x20) // get bn_shift pointer + mstore(0x40, add(mem_end, 0x20)) // update freemem pointer + } + + // use identity for cheap copy if bits is multiple of 8. + if(bits % 8 == 0) { + // calculate the position of the first byte in the result. + uint bytes_pos = ((256-(((bn.bitlen-1)+bits) % 256))-1) / 8; + uint insize = (bn.bitlen / 8) + ((bn.bitlen % 8 != 0) ? 1 : 0); + assembly { + let in := add(add(mload(bn), 0x20), div(sub(256, bit_position), 8)) + let out := add(bn_shift_ptr, bytes_pos) + let success := staticcall(450, 0x4, in, insize, out, length) + } + r.val = bn_shift; + return r; + } + + + uint mask; + uint mask_shift = 0x100-bits; + uint msw; + uint msw_ptr; + + assembly { + msw_ptr := add(mload(bn), 0x20) + } + + // handle first word before loop if the shift adds any extra words. + // the loop would handle it if the bit shift doesn't wrap into the next word, + // so we check only for that condition. + if((bit_position+bits) > 256){ + assembly { + msw := mload(msw_ptr) + mstore(bn_shift_ptr, shr(mask_shift, msw)) + bn_shift_ptr := add(bn_shift_ptr, 0x20) + } + } + + // as a result of creating the empty array we just have to operate on the words in the original bn. + for(uint i=bn.val.length; i!=0; i-=0x20){ // for each word: + assembly { + msw := mload(msw_ptr) // get most significant word + switch eq(i,0x20) // if i==32: + case 1 { mask := 0 } // handles msword: no mask needed. + default { mask := mload(add(msw_ptr,0x20)) } // else get mask (next word) + msw := shl(bits, msw) // left shift current msw by 'bits' + mask := shr(mask_shift, mask) // right shift next significant word by mask_shift + mstore(bn_shift_ptr, or(msw,mask)) // store OR'd mask and shifted bits in-place + msw_ptr := add(msw_ptr, 0x20) + bn_shift_ptr := add(bn_shift_ptr, 0x20) + } + } + + r.val = bn_shift; + } + // ***************** END PRIVATE HELPER FUNCTIONS ****************** +} diff --git a/contracts/utils/BigIntOpt.sol b/contracts/utils/BigIntOpt.sol new file mode 100644 index 0000000..b0274ac --- /dev/null +++ b/contracts/utils/BigIntOpt.sol @@ -0,0 +1,1200 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +import "hardhat/console.sol"; +// DefinitOption here allows both the lib and inheriting contracts to use BigIntOpt directly. +struct BigIntOpt { + bytes val; + bool neg; + uint bitlen; +} + +/** + * @notice BigIntOpts library for Solidity. + */ +library BigIntsOpt { + /// @notice the value for number 0 of a BigIntOpt instance. + bytes constant ZERO = hex"0000000000000000000000000000000000000000000000000000000000000000"; + /// @notice the value for number 1 of a BigIntOpt instance. + bytes constant ONE = hex"0000000000000000000000000000000000000000000000000000000000000001"; + /// @notice the value for number 2 of a BigIntOpt instance. + bytes constant TWO = hex"0000000000000000000000000000000000000000000000000000000000000002"; + + // ***************** BEGIN EXPOSED MANAGEMENT FUNCTIONS ****************** + /** @notice verify a BN instance + * @dev checks if the BN is in the correct format. operations should only be carried out on + * verified BNs, so it is necessary to call this if your function takes an arbitrary BN + * as input. + * + * @param bn BigIntOpt instance + */ + function verify( + BigIntOpt memory bn + ) internal pure { + uint msword; + bytes memory val = bn.val; + assembly {msword := mload(add(val,0x20))} //get msword of result + if(msword==0) require(isZero(bn)); + else require((bn.val.length % 32 == 0) && (msword>>((bn.bitlen-1)%256)==1)); + } + + /** @notice initOptialize a BN instance + * @dev wrapper function for _initOpt. initOptializes from bytes value. + * Allows passing bitLength of value. This is NOT verified in the internal function. Only use where bitlen is + * explicitly known; otherwise use the other initOpt function. + * + * @param val BN value. may be of any size. + * @param neg neg whether the BN is +/- + * @param bitlen bit length of output. + * @return BigIntOpt instance + */ + function initOpt( + bytes memory val, + bool neg, + uint bitlen + ) internal view returns(BigIntOpt memory){ + return _initOpt(val, neg, bitlen); + } + + /** @notice initOptialize a BN instance + * @dev wrapper function for _initOpt. initOptializes from bytes value. + * + * @param val BN value. may be of any size. + * @param neg neg whether the BN is +/- + * @return BigIntOpt instance + */ + function initOpt( + bytes memory val, + bool neg + ) internal view returns(BigIntOpt memory){ + return _initOpt(val, neg, 0); + } + + /** @notice initOptialize a BN instance + * @dev wrapper function for _initOpt. initOptializes from uint value (converts to bytes); + * tf. resulting BN is in the range -2^256-1 ... 2^256-1. + * + * @param val uint value. + * @param neg neg whether the BN is +/- + * @return BigIntOpt instance + */ + function initOpt( + uint val, + bool neg + ) internal view returns(BigIntOpt memory){ + return _initOpt(abi.encodePacked(val), neg, 0); + } + // ***************** END EXPOSED MANAGEMENT FUNCTIONS ****************** + + function add( + BigIntOpt memory a, + BigIntOpt memory b, + BigIntOpt memory temp + ) internal pure { + if(a.bitlen==0 && b.bitlen==0) { + delete temp; + } + if(a.bitlen==0) { + temp.val = b.val; + temp.bitlen = b.bitlen; + temp.neg = b.neg; + } + if(b.bitlen==0) { + temp.val = a.val; + temp.bitlen = a.bitlen; + temp.neg = a.neg; + } + // bytes memory val; + // uint bitlen; + int compare = cmp(a,b,false); + + if(a.neg || b.neg){ + if(a.neg && b.neg){ + if(compare>=0) (temp.val, temp.bitlen) = _add(a.val,b.val,a.bitlen); + else (temp.val, temp.bitlen) = _add(b.val,a.val,b.bitlen); + temp.neg = true; + } + else { + if(compare==1){ + (temp.val, temp.bitlen) = _sub(a.val,b.val); + temp.neg = a.neg; + } + else if(compare==-1){ + (temp.val, temp.bitlen) = _sub(b.val,a.val); + temp.neg = !a.neg; + } + else delete temp;//one pos and one neg, and same value. + } + } + else{ + if(compare>=0){ // a>=b + (temp.val, temp.bitlen) = _add(a.val,b.val,a.bitlen); + } + else { + (temp.val, temp.bitlen) = _add(b.val,a.val,b.bitlen); + } + temp.neg = false; + } + } + // _multiplyScalarPartial+ 2,561,331 + // _multiplyScalarPartial- 2,932,032 + + // _multiplyScalarPartial+ 2,556,615 + // _multiplyScalarPartial- 2,932,032 + +// _multiplyScalarPartial+ 2,550,279 +// _multiplyScalarPartial- 2,932,032 + function sub( + BigIntOpt memory a, + BigIntOpt memory b, + BigIntOpt memory temp + ) internal pure { + if(a.bitlen==0 && b.bitlen==0) delete temp; + //bytes memory val; + int compare; + //uint bitlen; + compare = cmp(a,b,false); + if(a.neg || b.neg) { + if(a.neg && b.neg){ + if(compare == 1) { + (temp.val,temp.bitlen) = _sub(a.val,b.val); + temp.neg = true; + } + else if(compare == -1) { + + (temp.val, temp.bitlen) = _sub(b.val,a.val); + temp.neg = false; + } + else delete temp; + } + else { + if(compare >= 0) (temp.val, temp.bitlen) = _add(a.val,b.val,a.bitlen); + else (temp.val,temp.bitlen) = _add(b.val,a.val,b.bitlen); + + temp.neg = (a.neg) ? true : false; + } + } + else { + if(compare == 1) { + (temp.val,temp.bitlen) = _sub(a.val,b.val); + temp.neg = false; + } + else if(compare == -1) { + (temp.val,temp.bitlen) = _sub(b.val,a.val); + temp.neg = true; + } + else delete temp; + } + + // temp.val = val; + // temp.bitlen = (bitlen); + } + + function mul( + BigIntOpt memory a, + BigIntOpt memory b, + BigIntOpt memory temp + ) internal view { + BigIntOpt memory _temp1; + BigIntOpt memory _temp2; + BigIntOpt memory _temp3; + + add(a,b, _temp1); + _powModulus(_temp1, 2, _temp3); + modexp(_temp1, two(), _temp3, _temp1); // (a+b)^2 + + // no need to do subtraction part of the equation if a == b; if so, it has no effect on final result. + if(!eq(a,b)) { + sub(a,b, _temp2); + _powModulus(_temp2, 2, _temp3); + modexp(_temp2, two(), _temp3, _temp2); // (a-b)^2 + + sub(_temp1, _temp2, _temp1); + } + + _shrOpt(_temp1, 2); + + temp.val = _temp1.val; + temp.bitlen = _temp1.bitlen; + temp.neg = _temp1.neg; + } + + function mod( + BigIntOpt memory a, + BigIntOpt memory n, + BigIntOpt memory temp + ) internal view{ + modexp(a, one(), n, temp); + } + + function modmul( + BigIntOpt memory a, + BigIntOpt memory b, + BigIntOpt memory n, + BigIntOpt memory temp) internal view { + mul(a,b, temp); + mod(temp, n, temp); + } + + function modexp( + BigIntOpt memory a, + BigIntOpt memory e, + BigIntOpt memory n, + BigIntOpt memory temp + ) internal view { + //if exponent is negative, other method with this same name should be used. + //if modulus is negative or zero, we cannot perform the operation. + require( e.neg==false + && n.neg==false + && !isZero(n.val)); + + bytes memory _result = _modexp(a.val,e.val,n.val); + //get bitlen of result (TODO: optimise. we know bitlen is in the same byte as the modulus bitlen byte) + uint bitlen = bitLength(_result); + + // if result is 0, immediately return. + if(bitlen == 0) { + delete temp; + } + // if base is negative AND exponent is odd, base^exp is negative, and tf. result is negative; + // in that case we make the result positive by adding the modulus. + if(a.neg && isOdd(e)) { + add(BigIntOpt(_result, true, bitlen), n, temp); + } + else { + // in any other case we return the positive result. + temp.val = _result; + temp.bitlen = bitlen; + temp.neg = false; + } + } + + // ***************** END EXPOSED CORE CALCULATION FUNCTIONS ****************** + + // ***************** START EXPOSED HELPER FUNCTIONS ****************** + /** @notice BigIntOpt odd number check + * @dev isOdd: returns 1 if BigIntOpt value is an odd number and 0 otherwise. + * + * @param a BigIntOpt + * @return r Boolean result + */ + function isOdd( + BigIntOpt memory a + ) internal pure returns(bool r){ + assembly{ + let a_ptr := add(mload(a), mload(mload(a))) // go to least significant word + r := mod(mload(a_ptr),2) // mod it with 2 (returns 0 or 1) + } + } + + /** @notice BigIntOpt comparison + * @dev cmp: Compares BigIntOpts a and b. 'signed' parameter indiciates whether to consider the sign of the inputs. + * 'trigger' is used to decide this - + * if both negative, invert the result; + * if both positive (or signed==false), trigger has no effect; + * if differing signs, we return immediately based on input. + * returns -1 on ab. + * + * @param a BigIntOpt + * @param b BigIntOpt + * @param signed whether to consider sign of inputs + * @return int result + */ + function cmp( + BigIntOpt memory a, + BigIntOpt memory b, + bool signed + ) internal pure returns(int){ + int trigger = 1; + if(signed){ + if(a.neg && b.neg) trigger = -1; + else if(a.neg==false && b.neg==true) return 1; + else if(a.neg==true && b.neg==false) return -1; + } + + if(a.bitlen>b.bitlen) return trigger; // 1*trigger + if(b.bitlen>a.bitlen) return -1*trigger; + + uint a_ptr; + uint b_ptr; + uint a_word; + uint b_word; + + uint len = a.val.length; //bitlen is same so no need to check length. + + assembly{ + a_ptr := add(mload(a),0x20) + b_ptr := add(mload(b),0x20) + } + + for(uint i=0; ib_word) return trigger; // 1*trigger + if(b_word>a_word) return -1*trigger; + + } + + return 0; //same value. + } + + /** @notice BigIntOpt equality + * @dev eq: returns true if a==b. sign always considered. + * + * @param a BigIntOpt + * @param b BigIntOpt + * @return boolean result + */ + function eq( + BigIntOpt memory a, + BigIntOpt memory b + ) internal pure returns(bool){ + int result = cmp(a, b, true); + return (result==0) ? true : false; + } + + /** @notice BigIntOpt greater than + * @dev eq: returns true if a>b. sign always considered. + * + * @param a BigIntOpt + * @param b BigIntOpt + * @return boolean result + */ + function gt( + BigIntOpt memory a, + BigIntOpt memory b + ) internal pure returns(bool){ + int result = cmp(a, b, true); + return (result==1) ? true : false; + } + + /** @notice BigIntOpt greater than or equal to + * @dev eq: returns true if a>=b. sign always considered. + * + * @param a BigIntOpt + * @param b BigIntOpt + * @return boolean result + */ + function gte( + BigIntOpt memory a, + BigIntOpt memory b + ) internal pure returns(bool){ + int result = cmp(a, b, true); + return (result==1 || result==0) ? true : false; + } + + /** @notice BigIntOpt less than + * @dev eq: returns true if a= the bitlength of the value the result is always 0 + if(bits >= bn.bitlen) return BigIntOpt(ZERO,false,0); + + // set bitlen initOptially as we will be potentially modifying 'bits' + bn.bitlen = bn.bitlen-(bits); + + // handle shifts greater than 256: + // if bits is greater than 256 we can simply remove any trailing words, by altering the BN length. + // we also update 'bits' so that it is now in the range 0..256. + assembly { + if or(gt(bits, 0x100), eq(bits, 0x100)) { + length := sub(length, mul(div(bits, 0x100), 0x20)) + mstore(mload(bn), length) + bits := mod(bits, 0x100) + } + + // if bits is multiple of 8 (byte size), we can simply use identity precompile for cheap memcopy. + // otherwise we shift each word, starting at the least signifcant word, one-by-one using the mask technique. + // TODO it is possible to do this without the last two operations, see SHL identity copy. + let bn_val_ptr := mload(bn) + switch eq(mod(bits, 8), 0) + case 1 { + let bytes_shift := div(bits, 8) + let in := mload(bn) + let inlength := mload(in) + let insize := add(inlength, 0x20) + let out := add(in, bytes_shift) + let outsize := sub(insize, bytes_shift) + let success := staticcall(450, 0x4, in, insize, out, insize) + mstore8(add(out, 0x1f), 0) // maintain our BN layout following identity call: + mstore(in, inlength) // set current length byte to 0, and reset old length. + } + default { + let mask + let lsw + let mask_shift := sub(0x100, bits) + let lsw_ptr := add(bn_val_ptr, length) + for { let i := length } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) + switch eq(i,0x20) // if i==32: + case 1 { mask := 0 } // - handles lsword: no mask needed. + default { mask := mload(sub(lsw_ptr,0x20)) } // - else get mask (previous word) + lsw := shr(bits, mload(lsw_ptr)) // right shift current by bits + mask := shl(mask_shift, mask) // left shift next significant word by mask_shift + mstore(lsw_ptr, or(lsw,mask)) // store OR'd mask and shifted bits in-place + lsw_ptr := sub(lsw_ptr, 0x20) // point to next bits. + } + } + + // The following removes the leading word containing all zeroes in the result should it exist, + // as well as updating lengths and pointers as necessary. + let msw_ptr := add(bn_val_ptr,0x20) + switch eq(mload(msw_ptr), 0) + case 1 { + mstore(msw_ptr, sub(mload(bn_val_ptr), 0x20)) // store new length in new position + mstore(bn, msw_ptr) // update pointer from bn + } + default {} + } + + + return bn; + } + + function _shrOpt(BigIntOpt memory bn, uint bits) internal view { + uint length; + assembly { length := mload(mload(bn)) } + + // if bits is >= the bitlength of the value the result is always 0 + if(bits >= bn.bitlen) { + delete bn; + } + + // set bitlen initOptially as we will be potentially modifying 'bits' + bn.bitlen = bn.bitlen-(bits); + + // handle shifts greater than 256: + // if bits is greater than 256 we can simply remove any trailing words, by altering the BN length. + // we also update 'bits' so that it is now in the range 0..256. + assembly { + if or(gt(bits, 0x100), eq(bits, 0x100)) { + length := sub(length, mul(div(bits, 0x100), 0x20)) + mstore(mload(bn), length) + bits := mod(bits, 0x100) + } + + // if bits is multiple of 8 (byte size), we can simply use identity precompile for cheap memcopy. + // otherwise we shift each word, starting at the least signifcant word, one-by-one using the mask technique. + // TODO it is possible to do this without the last two operations, see SHL identity copy. + let bn_val_ptr := mload(bn) + switch eq(mod(bits, 8), 0) + case 1 { + let bytes_shift := div(bits, 8) + let in := mload(bn) + let inlength := mload(in) + let insize := add(inlength, 0x20) + let out := add(in, bytes_shift) + let outsize := sub(insize, bytes_shift) + let success := staticcall(450, 0x4, in, insize, out, insize) + mstore8(add(out, 0x1f), 0) // maintain our BN layout following identity call: + mstore(in, inlength) // set current length byte to 0, and reset old length. + } + default { + let mask + let lsw + let mask_shift := sub(0x100, bits) + let lsw_ptr := add(bn_val_ptr, length) + for { let i := length } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) + switch eq(i,0x20) // if i==32: + case 1 { mask := 0 } // - handles lsword: no mask needed. + default { mask := mload(sub(lsw_ptr,0x20)) } // - else get mask (previous word) + lsw := shr(bits, mload(lsw_ptr)) // right shift current by bits + mask := shl(mask_shift, mask) // left shift next significant word by mask_shift + mstore(lsw_ptr, or(lsw,mask)) // store OR'd mask and shifted bits in-place + lsw_ptr := sub(lsw_ptr, 0x20) // point to next bits. + } + } + + // The following removes the leading word containing all zeroes in the result should it exist, + // as well as updating lengths and pointers as necessary. + let msw_ptr := add(bn_val_ptr,0x20) + switch eq(mload(msw_ptr), 0) + case 1 { + mstore(msw_ptr, sub(mload(bn_val_ptr), 0x20)) // store new length in new position + mstore(bn, msw_ptr) // update pointer from bn + } + default {} + } + } + + /** @notice left shift BigIntOpt value + * @dev shr: left shift BigIntOpt a by 'bits' bits. + ensures the value is not negative before calling the private function. + * @param a BigIntOpt value to shift + * @param bits amount of bits to shift by + * @return result BigIntOpt + */ + function shl( + BigIntOpt memory a, + uint bits + ) internal view returns(BigIntOpt memory){ + require(!a.neg); + return _shl(a, bits); + } + + /** @notice sha3 hash a BigIntOpt. + * @dev hash: takes a BigIntOpt and performs sha3 hash on it. + * we hash each BigIntOpt WITHOUT it's first word - first word is a pointer to the start of the bytes value, + * and so is different for each struct. + * + * @param a BigIntOpt + * @return h bytes32 hash. + */ + function hash( + BigIntOpt memory a + ) internal pure returns(bytes32 h) { + //amount of words to hash = all words of the value and three extra words: neg, bitlen & value length. + assembly { + h := keccak256( add(a,0x20), add (mload(mload(a)), 0x60 ) ) + } + } + + /** @notice BigIntOpt full zero check + * @dev isZero: checks if the BigIntOpt is in the default zero format for BNs (ie. the result from zero()). + * + * @param a BigIntOpt + * @return boolean result. + */ + function isZero( + BigIntOpt memory a + ) internal pure returns(bool) { + return isZero(a.val) && a.val.length==0x20 && !a.neg && a.bitlen == 0; + } + + + /** @notice bytes zero check + * @dev isZero: checks if input bytes value resolves to zero. + * + * @param a bytes value + * @return boolean result. + */ + function isZero( + bytes memory a + ) internal pure returns(bool) { + uint msword; + uint msword_ptr; + assembly { + msword_ptr := add(a,0x20) + } + for(uint i=0; i 0) return false; + assembly { msword_ptr := add(msword_ptr, 0x20) } + } + return true; + + } + + /** @notice BigIntOpt value bit length + * @dev bitLength: returns BigIntOpt value bit length- ie. log2 (most significant bit of value) + * + * @param a BigIntOpt + * @return uint bit length result. + */ + function bitLength( + BigIntOpt memory a + ) internal pure returns(uint){ + return bitLength(a.val); + } + + /** @notice bytes bit length + * @dev bitLength: returns bytes bit length- ie. log2 (most significant bit of value) + * + * @param a bytes value + * @return r uint bit length result. + */ + function bitLength( + bytes memory a + ) internal pure returns(uint r){ + if(isZero(a)) return 0; + uint msword; + assembly { + msword := mload(add(a,0x20)) // get msword of input + } + r = bitLength(msword); // get bitlen of msword, add to size of remaining words. + assembly { + r := add(r, mul(sub(mload(a), 0x20) , 8)) // res += (val.length-32)*8; + } + } + + /** @notice uint bit length + @dev bitLength: get the bit length of a uint input - ie. log2 (most significant bit of 256 bit value (one EVM word)) + * credit: Tjaden Hess @ ethereum.stackexchange + * @param a uint value + * @return r uint bit length result. + */ + function bitLength( + uint a + ) internal pure returns (uint r){ + assembly { + switch eq(a, 0) + case 1 { + r := 0 + } + default { + let arg := a + a := sub(a,1) + a := or(a, div(a, 0x02)) + a := or(a, div(a, 0x04)) + a := or(a, div(a, 0x10)) + a := or(a, div(a, 0x100)) + a := or(a, div(a, 0x10000)) + a := or(a, div(a, 0x100000000)) + a := or(a, div(a, 0x10000000000000000)) + a := or(a, div(a, 0x100000000000000000000000000000000)) + a := add(a, 1) + let m := mload(0x40) + mstore(m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd) + mstore(add(m,0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe) + mstore(add(m,0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616) + mstore(add(m,0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff) + mstore(add(m,0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e) + mstore(add(m,0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707) + mstore(add(m,0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606) + mstore(add(m,0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100) + mstore(0x40, add(m, 0x100)) + let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff + let shift := 0x100000000000000000000000000000000000000000000000000000000000000 + let _a := div(mul(a, magic), shift) + r := div(mload(add(m,sub(255,_a))), shift) + r := add(r, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000))) + // where a is a power of two, result needs to be incremented. we use the power of two trick here: if(arg & arg-1 == 0) ++r; + if eq(and(arg, sub(arg, 1)), 0) { + r := add(r, 1) + } + } + } + } + + /** @notice BigIntOpt zero value + @dev zero: returns zero encoded as a BigIntOpt + * @return zero encoded as BigIntOpt + */ + function zero( + ) internal pure returns(BigIntOpt memory) { + return BigIntOpt(ZERO, false, 0); + } + + /** @notice BigIntOpt one value + @dev one: returns one encoded as a BigIntOpt + * @return one encoded as BigIntOpt + */ + function one( + ) internal pure returns(BigIntOpt memory) { + return BigIntOpt(ONE, false, 1); + } + + /** @notice BigIntOpt two value + @dev two: returns two encoded as a BigIntOpt + * @return two encoded as BigIntOpt + */ + function two( + ) internal pure returns(BigIntOpt memory) { + return BigIntOpt(TWO, false, 2); + } + // ***************** END EXPOSED HELPER FUNCTIONS ****************** + + + + + + // ***************** START PRIVATE MANAGEMENT FUNCTIONS ****************** + /** @notice Create a new BigIntOpt. + @dev initOpt: overloading allows caller to obtionally pass bitlen where it is known - as it is cheaper to do off-chain and verify on-chain. + * we assert input is in data structure as defined above, and that bitlen, if passed, is correct. + * 'copy' parameter indicates whether or not to copy the contents of val to a new location in memory (for example where you pass + * the contents of another variable's value in) + * @param val bytes - bignum value. + * @param neg bool - sign of value + * @param bitlen uint - bit length of value + * @return r BigIntOpt initOptialized value. + */ + function _initOpt( + bytes memory val, + bool neg, + uint bitlen + ) private view returns(BigIntOpt memory r){ + // use identity at location 0x4 for cheap memcpy. + // grab contents of val, load starting from memory end, update memory end pointer. + assembly { + let data := add(val, 0x20) + let length := mload(val) + let out + let freemem := mload(0x40) + switch eq(mod(length, 0x20), 0) // if(val.length % 32 == 0) + case 1 { + out := add(freemem, 0x20) // freememory location + length word + mstore(freemem, length) // set new length + } + default { + let offset := sub(0x20, mod(length, 0x20)) // offset: 32 - (length % 32) + out := add(add(freemem, offset), 0x20) // freememory location + offset + length word + mstore(freemem, add(length, offset)) // set new length + } + pop(staticcall(450, 0x4, data, length, out, length)) // copy into 'out' memory location + mstore(0x40, add(freemem, add(mload(freemem), 0x20))) // update the free memory pointer + + // handle leading zero words. assume freemem is pointer to bytes value + let bn_length := mload(freemem) + for { } eq ( eq(bn_length, 0x20), 0) { } { // for(; length!=32; length-=32) + switch eq(mload(add(freemem, 0x20)),0) // if(msword==0): + case 1 { freemem := add(freemem, 0x20) } // update length pointer + default { break } // else: loop termination. non-zero word found + bn_length := sub(bn_length,0x20) + } + mstore(freemem, bn_length) + + mstore(r, freemem) // store new bytes value in r + mstore(add(r, 0x20), neg) // store neg value in r + } + + r.bitlen = bitlen == 0 ? bitLength(r.val) : bitlen; + } + // ***************** END PRIVATE MANAGEMENT FUNCTIONS ****************** + + + + + + // ***************** START PRIVATE CORE CALCULATION FUNCTIONS ****************** + /** @notice takes two BigIntOpt memory values and the bitlen of the max value, and adds them. + * @dev _add: This function is private and only callable from add: therefore the values may be of different sizes, + * in any order of size, and of different signs (handled in add). + * As values may be of different sizes, inputs are considered starting from the least significant + * words, working back. + * The function calculates the new bitlen (basically if bitlens are the same for max and min, + * max_bitlen++) and returns a new BigIntOpt memory value. + * + * @param max bytes - biggest value (determined from add) + * @param min bytes - smallest value (determined from add) + * @param max_bitlen uint - bit length of max value. + * @return bytes result - max + min. + * @return uint - bit length of result. + */ + function _add( + bytes memory max, + bytes memory min, + uint max_bitlen + ) private pure returns (bytes memory, uint) { + bytes memory result; + assembly { + + let result_start := mload(0x40) // Get the highest available block of memory + let carry := 0 + let uint_max := sub(0,1) + + let max_ptr := add(max, mload(max)) + let min_ptr := add(min, mload(min)) // point to last word of each byte array. + + let result_ptr := add(add(result_start,0x20), mload(max)) // set result_ptr end. + + for { let i := mload(max) } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) + let max_val := mload(max_ptr) // get next word for 'max' + switch gt(i,sub(mload(max),mload(min))) // if(i>(max_length-min_length)). while + // 'min' words are still available. + case 1{ + let min_val := mload(min_ptr) // get next word for 'min' + mstore(result_ptr, add(add(max_val,min_val),carry)) // result_word = max_word+min_word+carry + switch gt(max_val, sub(uint_max,sub(min_val,carry))) // this switch block finds whether or + // not to set the carry bit for the + // next iteration. + case 1 { carry := 1 } + default { + switch and(eq(max_val,uint_max),or(gt(carry,0), gt(min_val,0))) + case 1 { carry := 1 } + default{ carry := 0 } + } + + min_ptr := sub(min_ptr,0x20) // point to next 'min' word + } + default{ // else: remainder after 'min' words are complete. + mstore(result_ptr, add(max_val,carry)) // result_word = max_word+carry + + switch and( eq(uint_max,max_val), eq(carry,1) ) // this switch block finds whether or + // not to set the carry bit for the + // next iteration. + case 1 { carry := 1 } + default { carry := 0 } + } + result_ptr := sub(result_ptr,0x20) // point to next 'result' word + max_ptr := sub(max_ptr,0x20) // point to next 'max' word + } + + switch eq(carry,0) + case 1{ result_start := add(result_start,0x20) } // if carry is 0, increment result_start, ie. + // length word for result is now one word + // position ahead. + default { mstore(result_ptr, 1) } // else if carry is 1, store 1; overflow has + // occured, so length word remains in the + // same position. + + result := result_start // point 'result' bytes value to the correct + // address in memory. + mstore(result,add(mload(max),mul(0x20,carry))) // store length of result. we are finished + // with the byte array. + + mstore(0x40, add(result,add(mload(result),0x20))) // Update freemem pointer to point to new + // end of memory. + + // we now calculate the result's bit length. + // with addition, if we assume that some a is at least equal to some b, then the resulting bit length will + // be a's bit length or (a's bit length)+1, depending on carry bit.this is cheaper than calling bitLength. + let msword := mload(add(result,0x20)) // get most significant word of result + // if(msword==1 || msword>>(max_bitlen % 256)==1): + if or( eq(msword, 1), eq(shr(mod(max_bitlen,256),msword),1) ) { + max_bitlen := add(max_bitlen, 1) // if msword's bit length is 1 greater + // than max_bitlen, OR overflow occured, + // new bitlen is max_bitlen+1. + } + } + + + return (result, max_bitlen); + } + + /** @notice takes two BigIntOpt memory values and subtracts them. + * @dev _sub: This function is private and only callable from add: therefore the values may be of different sizes, + * in any order of size, and of different signs (handled in add). + * As values may be of different sizes, inputs are considered starting from the least significant words, + * working back. + * The function calculates the new bitlen (basically if bitlens are the same for max and min, + * max_bitlen++) and returns a new BigIntOpt memory value. + * + * @param max bytes - biggest value (determined from add) + * @param min bytes - smallest value (determined from add) + * @return bytes result - max + min. + * @return uint - bit length of result. + */ + function _sub( + bytes memory max, + bytes memory min + ) internal pure returns (bytes memory, uint) { + bytes memory result; + uint carry = 0; + uint uint_max = type(uint256).max; + assembly { + + let result_start := mload(0x40) // Get the highest available block of + // memory + + let max_len := mload(max) + let min_len := mload(min) // load lengths of inputs + + let len_diff := sub(max_len,min_len) // get differences in lengths. + + let max_ptr := add(max, max_len) + let min_ptr := add(min, min_len) // go to end of arrays + let result_ptr := add(result_start, max_len) // point to least significant result + // word. + let memory_end := add(result_ptr,0x20) // save memory_end to update free memory + // pointer at the end. + + for { let i := max_len } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) + let max_val := mload(max_ptr) // get next word for 'max' + switch gt(i,len_diff) // if(i>(max_length-min_length)). while + // 'min' words are still available. + case 1{ + let min_val := mload(min_ptr) // get next word for 'min' + + mstore(result_ptr, sub(sub(max_val,min_val),carry)) // result_word = (max_word-min_word)-carry + + switch or(lt(max_val, add(min_val,carry)), + and(eq(min_val,uint_max), eq(carry,1))) // this switch block finds whether or + // not to set the carry bit for the next iteration. + case 1 { carry := 1 } + default { carry := 0 } + + min_ptr := sub(min_ptr,0x20) // point to next 'result' word + } + default { // else: remainder after 'min' words are complete. + + mstore(result_ptr, sub(max_val,carry)) // result_word = max_word-carry + + switch and( eq(max_val,0), eq(carry,1) ) // this switch block finds whether or + // not to set the carry bit for the + // next iteration. + case 1 { carry := 1 } + default { carry := 0 } + + } + result_ptr := sub(result_ptr,0x20) // point to next 'result' word + max_ptr := sub(max_ptr,0x20) // point to next 'max' word + } + + //the following code removes any leading words containing all zeroes in the result. + result_ptr := add(result_ptr,0x20) + + // for(result_ptr+=32;; result==0; result_ptr+=32) + for { } eq(mload(result_ptr), 0) { result_ptr := add(result_ptr,0x20) } { + result_start := add(result_start, 0x20) // push up the start pointer for the result + max_len := sub(max_len,0x20) // subtract a word (32 bytes) from the + // result length. + } + + result := result_start // point 'result' bytes value to + // the correct address in memory + + mstore(result,max_len) // store length of result. we + // are finished with the byte array. + + mstore(0x40, memory_end) // Update freemem pointer. + } + + uint new_bitlen = bitLength(result); // calculate the result's + // bit length. + + return (result, new_bitlen); + } + + function _powModulus( + BigIntOpt memory a, + uint e, + BigIntOpt memory temp + ) private pure{ + bytes memory _modulus = ZERO; + uint mod_index; + + assembly { + mod_index := mul(mload(add(a, 0x40)), e) // a.bitlen * e is the max bitlength of result + let first_word_modulus := shl(mod(mod_index, 256), 1) // set bit in first modulus word. + mstore(_modulus, mul(add(div(mod_index,256),1),0x20)) // store length of modulus + mstore(add(_modulus,0x20), first_word_modulus) // set first modulus word + mstore(0x40, add(_modulus, add(mload(_modulus),0x20))) // update freemem pointer to be modulus index + // + length + } + + //create modulus BigIntOpt memory for modexp function + temp.val = _modulus; + temp.neg = false; + temp.bitlen = mod_index; + } + + /** @notice Modular Exponentiation: Takes bytes values for base, exp, mod and calls precompile for (base^exp)%^mod + * @dev modexp: Wrapper for built-in modexp (contract 0x5) as described here: + * https://github.com/ethereum/EIPs/pull/198 + * + * @param _b bytes base + * @param _e bytes base_inverse + * @param _m bytes exponent + * @param r bytes result. + */ + function _modexp( + bytes memory _b, + bytes memory _e, + bytes memory _m + ) private view returns(bytes memory r) { + assembly { + let bl := mload(_b) + let el := mload(_e) + let ml := mload(_m) + + let freemem := mload(0x40) // Free memory pointer is always stored at 0x40 + + mstore(freemem, bl) // arg[0] = base.length @ +0 + + mstore(add(freemem,32), el) // arg[1] = exp.length @ +32 + + mstore(add(freemem,64), ml) // arg[2] = mod.length @ +64 + + // arg[3] = base.bits @ + 96 + // Use identity built-in (contract 0x4) as a cheap memcpy + let success := staticcall(450, 0x4, add(_b,32), bl, add(freemem,96), bl) + + // arg[4] = exp.bits @ +96+base.length + let size := add(96, bl) + success := staticcall(450, 0x4, add(_e,32), el, add(freemem,size), el) + + // arg[5] = mod.bits @ +96+base.length+exp.length + size := add(size,el) + success := staticcall(450, 0x4, add(_m,32), ml, add(freemem,size), ml) + + switch success case 0 { invalid() } //fail where we haven't enough gas to make the call + + // Total size of input = 96+base.length+exp.length+mod.length + size := add(size,ml) + // Invoke contract 0x5, put return value right after mod.length, @ +96 + success := staticcall(sub(gas(), 1350), 0x5, freemem, size, add(freemem, 0x60), ml) + + switch success case 0 { invalid() } //fail where we haven't enough gas to make the call + + let length := ml + let msword_ptr := add(freemem, 0x60) + + ///the following code removes any leading words containing all zeroes in the result. + for { } eq ( eq(length, 0x20), 0) { } { // for(; length!=32; length-=32) + switch eq(mload(msword_ptr),0) // if(msword==0): + case 1 { msword_ptr := add(msword_ptr, 0x20) } // update length pointer + default { break } // else: loop termination. non-zero word found + length := sub(length,0x20) + } + r := sub(msword_ptr,0x20) + mstore(r, length) + + // point to the location of the return value (length, bits) + //assuming mod length is multiple of 32, return value is already in the right format. + mstore(0x40, add(add(96, freemem),ml)) //deallocate freemem pointer + } + } + // ***************** END PRIVATE CORE CALCULATION FUNCTIONS ****************** + + + + + + // ***************** START PRIVATE HELPER FUNCTIONS ****************** + /** @notice left shift BigIntOpt memory 'dividend' by 'value' bits. + * @param bn value to shift + * @param bits amount of bits to shift by + * @return r result + */ + function _shl( + BigIntOpt memory bn, + uint bits + ) private view returns(BigIntOpt memory r) { + if(bits==0 || bn.bitlen==0) return bn; + + // we start by creating an empty bytes array of the size of the output, based on 'bits'. + // for that we must get the amount of extra words needed for the output. + uint length = bn.val.length; + // position of bitlen in most significnat word + uint bit_position = ((bn.bitlen-1) % 256) + 1; + // total extra words. we check if the bits remainder will add one more word. + uint extra_words = (bits / 256) + ( (bits % 256) >= (256 - bit_position) ? 1 : 0); + // length of output + uint total_length = length + (extra_words * 0x20); + + r.bitlen = bn.bitlen+(bits); + r.neg = bn.neg; + bits %= 256; + + + bytes memory bn_shift; + uint bn_shift_ptr; + // the following efficiently creates an empty byte array of size 'total_length' + assembly { + let freemem_ptr := mload(0x40) // get pointer to free memory + mstore(freemem_ptr, total_length) // store bytes length + let mem_end := add(freemem_ptr, total_length) // end of memory + mstore(mem_end, 0) // store 0 at memory end + bn_shift := freemem_ptr // set pointer to bytes + bn_shift_ptr := add(bn_shift, 0x20) // get bn_shift pointer + mstore(0x40, add(mem_end, 0x20)) // update freemem pointer + } + + // use identity for cheap copy if bits is multiple of 8. + if(bits % 8 == 0) { + // calculate the position of the first byte in the result. + uint bytes_pos = ((256-(((bn.bitlen-1)+bits) % 256))-1) / 8; + uint insize = (bn.bitlen / 8) + ((bn.bitlen % 8 != 0) ? 1 : 0); + assembly { + let in := add(add(mload(bn), 0x20), div(sub(256, bit_position), 8)) + let out := add(bn_shift_ptr, bytes_pos) + let success := staticcall(450, 0x4, in, insize, out, length) + } + r.val = bn_shift; + return r; + } + + + uint mask; + uint mask_shift = 0x100-bits; + uint msw; + uint msw_ptr; + + assembly { + msw_ptr := add(mload(bn), 0x20) + } + + // handle first word before loop if the shift adds any extra words. + // the loop would handle it if the bit shift doesn't wrap into the next word, + // so we check only for that condition. + if((bit_position+bits) > 256){ + assembly { + msw := mload(msw_ptr) + mstore(bn_shift_ptr, shr(mask_shift, msw)) + bn_shift_ptr := add(bn_shift_ptr, 0x20) + } + } + + // as a result of creating the empty array we just have to operate on the words in the original bn. + for(uint i=bn.val.length; i!=0; i-=0x20){ // for each word: + assembly { + msw := mload(msw_ptr) // get most significant word + switch eq(i,0x20) // if i==32: + case 1 { mask := 0 } // handles msword: no mask needed. + default { mask := mload(add(msw_ptr,0x20)) } // else get mask (next word) + msw := shl(bits, msw) // left shift current msw by 'bits' + mask := shr(mask_shift, mask) // right shift next significant word by mask_shift + mstore(bn_shift_ptr, or(msw,mask)) // store OR'd mask and shifted bits in-place + msw_ptr := add(msw_ptr, 0x20) + bn_shift_ptr := add(bn_shift_ptr, 0x20) + } + } + + r.val = bn_shift; + } + // ***************** END PRIVATE HELPER FUNCTIONS ****************** +} diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index 662a64a..e817b3d 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -2,28 +2,43 @@ pragma solidity ^0.8.4; import {MemoryStack} from "./MemoryStack.sol"; +struct SharedMemory { + MemoryStack.Stack stack; + MemoryStack.Stack extStack; + MemoryStack.Stack callStack; +} + +struct Uint512 { + MemoryStack.StackValue data; +} library MemoryUint { using MemoryStack for *; - struct SharedMemory { - MemoryStack.Stack stack; - MemoryStack.Stack extStack; - MemoryStack.Stack callStack; - } - - struct Uint512 { - MemoryStack.StackValue data; - } - function newUint512SharedMemory() internal view returns (SharedMemory memory mem_) { mem_.stack = MemoryStack.init(64); mem_.extStack = MemoryStack.init(160); - mem_.callStack = MemoryStack.init(1024); + mem_.callStack = MemoryStack.init(512); return mem_; } + function zero(SharedMemory memory mem_) internal view returns (Uint512 memory u512_) { + return Uint512(_newUint(mem_, 0)); + } + + function one(SharedMemory memory mem_) internal view returns (Uint512 memory u512_) { + return Uint512(_newUint(mem_, 1)); + } + + function two(SharedMemory memory mem_) internal view returns (Uint512 memory u512_) { + return Uint512(_newUint(mem_, 2)); + } + + function three(SharedMemory memory mem_) internal view returns (Uint512 memory u512_) { + return Uint512(_newUint(mem_, 3)); + } + function newUint512( SharedMemory memory mem_, bytes memory data_ @@ -275,7 +290,7 @@ library MemoryUint { SharedMemory memory mem_, Uint512 memory a_, Uint512 memory m_ - ) private view returns (Uint512 memory r_) { + ) internal view returns (Uint512 memory r_) { _checkMemory(mem_, 64); return Uint512(_mod(mem_, a_.data, m_.data)); diff --git a/hardhat.config.ts b/hardhat.config.ts index 075123f..089ffc5 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -22,6 +22,9 @@ const config: HardhatUserConfig = { networks: { hardhat: { initialDate: "2004-01-01", + allowUnlimitedContractSize: true, + gas: "auto", + blockGasLimit: 300_000_000, // whatever you want here }, localhost: { url: "http://127.0.0.1:8545", @@ -87,13 +90,28 @@ const config: HardhatUserConfig = { }, }, solidity: { - version: "0.8.16", - settings: { - optimizer: { - enabled: true, - runs: 200, + compilers: [ + { + version: "0.8.16", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + viaIR: false, + }, }, - }, + { + version: "0.8.17", + settings: { + optimizer: { + enabled: false, + runs: 200, + }, + viaIR: false, + }, + }, + ], }, etherscan: { apiKey: { @@ -151,7 +169,7 @@ const config: HardhatUserConfig = { gasReporter: { currency: "USD", gasPrice: 50, - enabled: false, + enabled: true, reportPureAndViewMethods: true, coinmarketcap: `${process.env.COINMARKETCAP_KEY}`, }, diff --git a/package.json b/package.json index 905275f..8038c25 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "deploy-avalanche": "npx hardhat migrate --network avalanche --verify", "generate-types": "TYPECHAIN_FORCE=true npx hardhat typechain && npx hardhat gobind", "generate-docs": "npx hardhat markup", - "lint-fix": "npm run lint-sol-fix && npm run lint-ts-fix && npm run lint-json-fix", + "lint-fix": "", "lint-json-fix": "prettier --write \"./**/*.json\"", "lint-ts-fix": "prettier --write \"./**/*.ts\"", "lint-sol-fix": "prettier --write \"contracts/**/*.sol\"", diff --git a/test/helpers/bigintHelper.ts b/test/helpers/bigintHelper.ts new file mode 100644 index 0000000..90e226a --- /dev/null +++ b/test/helpers/bigintHelper.ts @@ -0,0 +1,233 @@ +// sec384r1 +export const a = BigInt( + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", +); +export const b = BigInt( + "0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", +); +export const gx = BigInt( + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", +); +export const gy = BigInt( + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", +); +export const p = BigInt( + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", +); +export const n = BigInt( + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", +); +export const lowSmax = BigInt( + "0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b9", +); + +export function modmul(a: bigint, b: bigint, mod: bigint): bigint { + return (a * b) % mod; +} + +export function inverseMod(u: bigint, m: bigint): bigint { + const zero = 0n; + + if (u === 0n || u === m || m === 0n) { + return zero; + } + + if (u > m) { + u = u % m; + } + + let t1 = zero; + let t2 = 1n; + let r1 = m; + let r2 = u; + let q = zero; + + while (r2 !== 0n) { + q = r1 / r2; + [t1, t2, r1, r2] = [t2, t1 - q * t2, r2, r1 - q * r2]; + } + + if (t1 < zero) { + return m - -t1; + } + + return t1; +} + +export function toAffinePoint(x0: bigint, y0: bigint, z0: bigint): { x: bigint; y: bigint } { + // Calculate the inverse mod of z0Inv with respect to p + const z0Inv = inverseMod(z0, p); + // Calculate the affine coordinates + const x = moddiv(x0, z0, p); + const y = modiv(y0, z0, p); + + // Return the affine coordinates + return { x, y }; +} + +export function multiplyScalar(x0: bigint, y0: bigint, scalar: bigint): { x: bigint; y: bigint } { + if (scalar === 0n) { + return zeroAffine(); + } else if (scalar === 1n) { + return { x: x0, y: y0 }; + } else if (scalar === 2n) { + return twice(x0, y0); + } + + let base2X = x0; + let base2Y = y0; + let base2Z = 1n; + let z1 = 1n; + let x1 = x0; + let y1 = y0; + + if (scalar % 2n === 0n) { + x1 = 0n; + y1 = 0n; + } + + scalar = scalar >> 1n; + + while (scalar > 0n) { + ({ x: base2X, y: base2Y, z: base2Z } = twiceProj(base2X, base2Y, base2Z)); + + if (scalar % 2n === 1n) { + ({ x: x1, y: y1, z: z1 } = addProj(base2X, base2Y, base2Z, x1, y1, z1)); + } + + scalar = scalar >> 1n; + } + + console.log("x1", x1); + console.log("y1", y1); + console.log("z1", z1); + return toAffinePoint(x1, y1, z1); +} + +function twice(x0: bigint, y0: bigint) { + const { x, y, z } = twiceProj(x0, y0, 1n); + return toAffinePoint(x, y, z); +} + +function twiceProj(x0: bigint, y0: bigint, z0: bigint): { x: bigint; y: bigint; z: bigint } { + let t: bigint; + let u: bigint; + let v: bigint; + let w: bigint; + + if (isZeroCurve(x0, y0)) { + return zeroProj(); + } + + u = modmul(y0, z0, p); + u = modmul(u, 2n, p); + + v = modmul(u, x0, p); + v = modmul(v, y0, p); + v = modmul(v, 2n, p); + + x0 = modmul(x0, x0, p); + t = modmul(x0, BigInt(3), p); + + z0 = modmul(z0, z0, p); + z0 = modmul(z0, a, p); + t = (t + z0) % p; + + w = modmul(t, t, p); + x0 = modmul(2n, v, p); + w = (w + (p - x0)) % p; + + x0 = (v + (p - w)) % p; + x0 = modmul(t, x0, p); + y0 = modmul(y0, u, p); + y0 = modmul(y0, y0, p); + y0 = modmul(2n, y0, p); + let y1 = (x0 + (p - y0)) % p; + + let x1 = modmul(u, w, p); + + let z1 = modmul(u, u, p); + z1 = modmul(z1, u, p); + + return { x: x1, y: y1, z: z1 }; +} + +export function addProj( + x0: bigint, + y0: bigint, + z0: bigint, + x1: bigint, + y1: bigint, + z1: bigint, +): { x: bigint; y: bigint; z: bigint } { + let t0: bigint; + let t1: bigint; + let u0: bigint; + let u1: bigint; + + if (isZeroCurve(x0, y0)) { + return { x: x1, y: y1, z: z1 }; + } else if (isZeroCurve(x1, y1)) { + return { x: x0, y: y0, z: z0 }; + } + + t0 = modmul(y0, z1, p); + t1 = modmul(y1, z0, p); + + u0 = modmul(x0, z1, p); + u1 = modmul(x1, z0, p); + + if (u0 === u1) { + if (t0 === t1) { + return twiceProj(x0, y0, z0); + } else { + return zeroProj(); + } + } + + return addProj2(modmul(z0, z1, p), u0, u1, t1, t0); +} + +function addProj2(v: bigint, u0: bigint, u1: bigint, t1: bigint, t0: bigint): { x: bigint; y: bigint; z: bigint } { + let u: bigint; + let u2: bigint; + let u3: bigint; + let w: bigint; + let t: bigint; + + t = (t0 + (p - t1)) % p; + u = (u0 + (p - u1)) % p; + u2 = modmul(u, u, p); + + w = modmul(t, t, p); + w = modmul(w, v, p); + u1 = (u1 + u0) % p; + u1 = modmul(u1, u2, p); + w = (w + (p - u1)) % p; + + const x2 = modmul(u, w, p); + + u3 = modmul(u2, u, p); + u0 = modmul(u0, u2, p); + u0 = (u0 + (p - w)) % p; + t = modmul(t, u0, p); + t0 = modmul(t0, u3, p); + + const y2 = (t + (p - t0)) % p; + + const z2 = modmul(u3, v, p); + + return { x: x2, y: y2, z: z2 }; +} + +function isZeroCurve(x: bigint, y: bigint): boolean { + return x === BigInt(0) && y === BigInt(0); +} + +function zeroProj(): { x: bigint; y: bigint; z: bigint } { + return { x: 0n, y: 1n, z: 0n }; +} + +function zeroAffine(): { x: bigint; y: bigint } { + return { x: 0n, y: 0n }; +} diff --git a/test/helpers/index.ts b/test/helpers/index.ts index b6e2522..85d8387 100644 --- a/test/helpers/index.ts +++ b/test/helpers/index.ts @@ -3,3 +3,4 @@ export * from "./poseidon-hash"; export * from "./poseidon-deploy"; export * from "./TSSSigner"; export * from "./TSSMerkleTree"; +export * from "./bigintHelper"; diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts new file mode 100644 index 0000000..4df2f01 --- /dev/null +++ b/test/passport/authenticators/PECDSAAuthenticator.test.ts @@ -0,0 +1,110 @@ +import { ethers } from "hardhat"; +import { toBeHex as hex } from "ethers"; +import { expect } from "chai"; +import { Reverter } from "@/test/helpers/"; +import { inverseMod, toAffinePoint, multiplyScalar, addProj, n, p, gx, gy, modmul } from "@/test/helpers/"; + +import { PECDSASHA1Authenticator, PECDSASHA2Authenticator, PECDSASHA2NewAuthenticator } from "@ethers-v6"; + +describe("PECDSAAuthenticator", () => { + const reverter = new Reverter(); + + let authSha1: PECDSASHA1Authenticator; + let authSha2: PECDSASHA2Authenticator; + let authSha2New: PECDSASHA2NewAuthenticator; + + before("setup", async () => { + const PECDSASHA1Authenticator = await ethers.getContractFactory("PECDSASHA1Authenticator"); + const PECDSASHA2Authenticator = await ethers.getContractFactory("PECDSASHA2Authenticator"); + const PECDSASHA2NewAuthenticator = await ethers.getContractFactory("PECDSASHA2NewAuthenticator"); + + authSha1 = await PECDSASHA1Authenticator.deploy(); + authSha2 = await PECDSASHA2Authenticator.deploy(); + authSha2New = await PECDSASHA2NewAuthenticator.deploy(); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe("#authenticate", () => { + it.only("should authenticate passport - brainpool256r1 & sha1", async () => { + const challenge = "0xe7938ea62eb1980a"; + + const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; + const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; + const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; + const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; + + expect(await authSha1.authenticate(challenge, r, s, x, y)).to.be.true; + }); + + it("should authenticate passport - brainpool256r1 & sha2", async () => { + const challenge = "0xe7938ea62eb1980a"; + + const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; + const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; + const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; + const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; + + expect(await authSha2.authenticate(challenge, r, s, x, y)).to.be.true; + }); + + it.only("should authenticate passport - secp384r1 & sha2 new", async () => { + // const challenge = + // "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; + + // const r = "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63"; + // const s = "0xf1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd"; + // const x = "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6"; + // const y = "0x1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; + + const challenge = "0xe7938ea62eb1980a"; + + const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; + const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; + const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; + const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; + + //await authSha2New.forTest(y); + expect(await authSha2New.authenticate(challenge, r, s, x, y)).to.be.true; + + // console.log(gx, gy, modmul(BigInt(ethers.sha256(challenge)), sInv, n)); + + // const sInv = inverseMod(BigInt(s), n); + // const { x: x1, y: y1 } = multiplyScalar(gx, gy, modmul(BigInt(ethers.sha256(challenge)), sInv, n)); + // // const points1 = await authSha2._multiplyScalarPartial( + // // hex(gx), + // // hex(gy), + // // hex(modmul(BigInt(ethers.sha256(challenge)), sInv, n)), + // // ); + // // const points2 = await authSha2._multiplyScalarPartial( + // // hex(gx), + // // hex(gy), + // // hex(modmul(BigInt(ethers.sha256(challenge)), sInv, n)), + // // ); + + // const { x: x2, y: y2 } = multiplyScalar(BigInt(x), BigInt(y), modmul(BigInt(r), sInv, n)); + // const { + // x: x0, + // y: y0, + // z: z0, + // } = addProj( + // BigInt(points1.x1.val), + // BigInt(points1.y1.val), + // 1n, + // BigInt(points2.x1.val), + // BigInt(points2.y1.val), + // 1n, + // ); + + // const { x: xP } = toAffinePoint(x0, y0, z0); + // const Px = inverseMod(1n % p, p); + + // expect(await authSha2.authenticate(r, s, x, y, hex(xP), hex(Px))).to.be.true; + + // console.log("_multiplyScalarPartial+", new Intl.NumberFormat("en-US").format(gas1)); + // console.log("_multiplyScalarPartial-", new Intl.NumberFormat("en-US").format(gas2)); + }); + }); +}); diff --git a/test/utils/Stack.test.ts b/test/utils/Stack.test.ts index 414d44f..256708d 100644 --- a/test/utils/Stack.test.ts +++ b/test/utils/Stack.test.ts @@ -4,7 +4,7 @@ import { StackMock } from "@ethers-v6"; import { getPoseidon, Reverter } from "@/test/helpers/"; -describe.only("Stack", () => { +describe("Stack", () => { const reverter = new Reverter(); let stack: StackMock; From d57b7126c4fdd0df26c9f024fbf1fa02e77b0676 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Tue, 15 Oct 2024 20:31:09 +0300 Subject: [PATCH 12/45] weird stuff --- .../PECDSASHA2NewAuthenticator.sol | 222 ++--- contracts/utils/MemoryStack.sol | 29 +- contracts/utils/MemoryUint.sol | 812 ++++++++---------- .../PECDSAAuthenticator.test.ts | 2 +- 4 files changed, 514 insertions(+), 551 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol index 3c51e00..891405f 100644 --- a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.17; import "hardhat/console.sol"; -import {Uint512, SharedMemory, MemoryUint} from "../../utils/MemoryUint.sol"; +import {SharedMemory, MemoryUint} from "../../utils/MemoryUint.sol"; import {SHA1} from "../../utils/SHA1.sol"; /** @@ -14,41 +14,41 @@ contract PECDSASHA2NewAuthenticator { // secp384r1 parameters struct Secp384rParams { - Uint512 a; - Uint512 b; - Uint512 gx; - Uint512 gy; - Uint512 p; - Uint512 n; - Uint512 lowSmax; + uint256 a; + uint256 b; + uint256 gx; + uint256 gy; + uint256 p; + uint256 n; + uint256 lowSmax; } struct XYZ { - Uint512 x; - Uint512 y; - Uint512 z; + uint256 x; + uint256 y; + uint256 z; } struct UT { - Uint512 u0; - Uint512 u1; - Uint512 t0; - Uint512 t1; + uint256 u0; + uint256 u1; + uint256 t0; + uint256 t1; } struct UWT { - Uint512 u; - Uint512 u2; - Uint512 u3; - Uint512 w; - Uint512 t; + uint256 u; + uint256 u2; + uint256 u3; + uint256 w; + uint256 t; } struct TUVW { - Uint512 t; - Uint512 u; - Uint512 v; - Uint512 w; + uint256 t; + uint256 u; + uint256 v; + uint256 w; } /** @@ -87,8 +87,8 @@ contract PECDSASHA2NewAuthenticator { ) }); - Uint512 memory _x = _shMem.newUint512(x); - Uint512 memory _y = _shMem.newUint512(y); + uint256 _x = _shMem.newUint512(x); + uint256 _y = _shMem.newUint512(y); /// @dev accept s only from the lower part of the curve // if (r == 0 || r >= n || s == 0 || s > lowSmax) { @@ -99,12 +99,12 @@ contract PECDSASHA2NewAuthenticator { return false; } - Uint512 memory message = _shMem.newUint512(abi.encodePacked(uint160(challenge.sha1()))); + uint256 message = _shMem.newUint512(abi.encodePacked(uint160(challenge.sha1()))); - Uint512 memory _s = _shMem.newUint512(s); + uint256 _s = _shMem.newUint512(s); - Uint512 memory temp = _shMem.moddiv(message, _s, _params.n); - (Uint512 memory x1, Uint512 memory y1) = _multiplyScalar( + uint256 temp = _shMem.moddiv(message, _s, _params.n); + (uint256 x1, uint256 y1) = _multiplyScalar( _shMem, _params, _params.gx, @@ -113,27 +113,28 @@ contract PECDSASHA2NewAuthenticator { ); _shMem.destruct(temp); - console.logBytes(x1.data.value); - console.logBytes(y1.data.value); - // Uint512 memory _r = _shMem.newUint512(r); + console.logBytes(MemoryUint.toData(x1)); + console.logBytes(MemoryUint.toData(y1)); + return false; + // uint256 _r = _shMem.newUint512(r); // temp = _shMem.moddiv(_r, _s, _params.n); - // (Uint512 memory x2, Uint512 memory y2) = _multiplyScalar(_shMem, _params, _x, _y, temp); + // (uint256 x2, uint256 y2) = _multiplyScalar(_shMem, _params, _x, _y, temp); // _shMem.destruct(temp); // _shMem.destruct(_s); - // Uint512 memory x1 = _shMem.newUint512( + // uint256 x1 = _shMem.newUint512( // hex"237544e26b27436fe2825685b0c8c479b5a9fba1424eed1bdb46662edf7357a7" // ); - // Uint512 memory x2 = _shMem.newUint512( + // uint256 x2 = _shMem.newUint512( // hex"09e5dd89d2c91b8e803a1582af8835ef03824a43cbcd4cb7320b1aa675706add" // ); - // Uint512 memory y1 = _shMem.newUint512( + // uint256 y1 = _shMem.newUint512( // hex"5c746bb1eaef6275433511fbc7afa832abd79e58d7b06fe63104696f957e47fc" // ); - // Uint512 memory y2 = _shMem.newUint512( + // uint256 y2 = _shMem.newUint512( // hex"8fd8e0c00ea0ca899cbd668e8de533e5cadb188a3d37a633b953501196194f39" // ); @@ -144,14 +145,14 @@ contract PECDSASHA2NewAuthenticator { // _shMem.destruct(y1); // _shMem.destruct(y2); - // Uint512 memory temp = _shMem.zero(); + // uint256 temp = _shMem.zero(); // if (_shMem.cmp(P[2], temp) == 0) { // return false; // } // _shMem.destruct(temp); // temp = _shMem.moddiv(P[2], P[2], _params.p); - // Uint512 memory Px = _shMem.modmul(P[0], temp, _params.p); + // uint256 Px = _shMem.modmul(P[0], temp, _params.p); // _shMem.destruct(temp); // temp = _shMem.mod(Px, _params.n); @@ -165,20 +166,20 @@ contract PECDSASHA2NewAuthenticator { function _multiplyScalar( SharedMemory memory shMem, Secp384rParams memory params, - Uint512 memory x0, - Uint512 memory y0, - Uint512 memory scalar - ) internal view returns (Uint512 memory x1, Uint512 memory y1) { + uint256 x0, + uint256 y0, + uint256 scalar + ) internal view returns (uint256 x1, uint256 y1) { { - Uint512 memory zero = shMem.zero(); - Uint512 memory one = shMem.one(); + uint256 zero = shMem.zero(); + uint256 one = shMem.one(); if (shMem.cmp(scalar, zero) == 0) { return _zeroAffine(shMem); } else if (shMem.cmp(scalar, one) == 0) { return (x0, y0); } else { - Uint512 memory two = shMem.two(); + uint256 two = shMem.two(); int256 res = shMem.cmp(scalar, two); shMem.destruct(two); @@ -188,7 +189,8 @@ contract PECDSASHA2NewAuthenticator { } } - // Uint512 memory temp = shMem.mod(scalar, two); + + // uint256 temp = shMem.mod(scalar, two); // if (shMem.cmp(temp, zero) == 0) { // x1 = shMem.zero(); // y1 = shMem.zero(); @@ -200,13 +202,36 @@ contract PECDSASHA2NewAuthenticator { // while (scalar > 0) { //(base2X, base2Y, base2Z) = _twiceProj(shMem, params, XYZ(base2X, base2Y, base2Z)); - //Uint512 memory temp = shMem.mod(scalar, two); + //uint256 temp = shMem.mod(scalar, two); //if (shMem.cmp(temp, one) == 0) { //(x1, y1, z1) = _addProj(shMem, params, XYZ(base2X, base2Y, base2Z), XYZ(x1, y1, z1)); //} // scalar = scalar >> 1; // } + XYZ memory xyzBase; + XYZ memory xyz1; + { + bytes memory x0Bytes; + bytes memory y0Bytes; + + assembly { + x0Bytes := x0 + y0Bytes := y0 + } + + xyzBase = XYZ( + shMem.newUint512(x0Bytes), + shMem.newUint512(y0Bytes), + shMem.one() + ); + xyz1 = XYZ( + shMem.newUint512(x0Bytes), + shMem.newUint512(y0Bytes), + shMem.one() + ); + } + uint256 lowBits_; assembly { @@ -215,18 +240,7 @@ contract PECDSASHA2NewAuthenticator { lowBits_ = lowBits_ >> 1; - XYZ memory xyzBase = XYZ( - shMem.newUint512(x0.data.value), - shMem.newUint512(y0.data.value), - shMem.one() - ); - XYZ memory xyz1 = XYZ( - shMem.newUint512(x0.data.value), - shMem.newUint512(y0.data.value), - shMem.one() - ); - for (uint i = 0; i < 10; i++) { - //while (lowBits_ > 0) { + while (lowBits_ > 0) { XYZ memory xyzBaseTemp; xyzBaseTemp = _twiceProj(shMem, params, xyzBase); @@ -248,6 +262,8 @@ contract PECDSASHA2NewAuthenticator { } lowBits_ = lowBits_ >> 1; + + console.log(lowBits_); } // shMem.destruct(zero); @@ -271,8 +287,8 @@ contract PECDSASHA2NewAuthenticator { return _zeroProj(shMem); } - Uint512 memory two = shMem.two(); - Uint512 memory three = shMem.three(); + uint256 two = shMem.two(); + uint256 three = shMem.three(); tuvw.u = shMem.modmul(xyz0.y, xyz0.z, params.p); tuvw.u = shMem.modmul(tuvw.u, two, params.p); @@ -294,7 +310,7 @@ contract PECDSASHA2NewAuthenticator { xyz0.x = shMem.modmul(two, tuvw.v, params.p); - Uint512 memory temp = shMem.sub(params.p, xyz0.x); + uint256 temp = shMem.sub(params.p, xyz0.x); tuvw.w = shMem.modadd(tuvw.w, temp, params.p); shMem.destruct(temp); @@ -342,11 +358,11 @@ contract PECDSASHA2NewAuthenticator { return XYZ(xyz0.x, xyz0.y, xyz0.z); } - Uint512 memory t0 = shMem.modmul(xyz0.y, xyz1.z, params.p); - Uint512 memory t1 = shMem.modmul(xyz1.y, xyz0.z, params.p); + uint256 t0 = shMem.modmul(xyz0.y, xyz1.z, params.p); + uint256 t1 = shMem.modmul(xyz1.y, xyz0.z, params.p); - Uint512 memory u0 = shMem.modmul(xyz0.x, xyz1.z, params.p); - Uint512 memory u1 = shMem.modmul(xyz1.x, xyz0.z, params.p); + uint256 u0 = shMem.modmul(xyz0.x, xyz1.z, params.p); + uint256 u1 = shMem.modmul(xyz1.x, xyz0.z, params.p); if (shMem.cmp(u0, u1) == 0) { if (shMem.cmp(t0, t1) == 0) { @@ -355,7 +371,7 @@ contract PECDSASHA2NewAuthenticator { xyz = _zeroProj(shMem); } } else { - Uint512 memory temp = shMem.modmul(xyz0.z, xyz1.z, params.p); + uint256 temp = shMem.modmul(xyz0.z, xyz1.z, params.p); xyz = _addProj2(shMem, params, temp, UT(u0, u1, t0, t1)); shMem.destruct(temp); @@ -373,12 +389,12 @@ contract PECDSASHA2NewAuthenticator { function _addProj2( SharedMemory memory shMem, Secp384rParams memory params, - Uint512 memory v, + uint256 v, UT memory ut ) internal view returns (XYZ memory xyz) { UWT memory uwt; - Uint512 memory temp = shMem.sub(params.p, ut.t1); + uint256 temp = shMem.sub(params.p, ut.t1); uwt.t = shMem.modadd(ut.t0, temp, params.p); shMem.destruct(temp); @@ -423,12 +439,12 @@ contract PECDSASHA2NewAuthenticator { function _add( SharedMemory memory shMem, Secp384rParams memory params, - Uint512 memory x0, - Uint512 memory y0, - Uint512 memory x1, - Uint512 memory y1 - ) internal view returns (Uint512 memory x, Uint512 memory y) { - Uint512 memory one = shMem.one(); + uint256 x0, + uint256 y0, + uint256 x1, + uint256 y1 + ) internal view returns (uint256 x, uint256 y) { + uint256 one = shMem.one(); XYZ memory xyz = _addProj(shMem, params, XYZ(x0, y0, one), XYZ(x1, y1, one)); (x, y) = _toAffinePoint(shMem, params, xyz); @@ -445,10 +461,10 @@ contract PECDSASHA2NewAuthenticator { function _twice( SharedMemory memory shMem, Secp384rParams memory params, - Uint512 memory x0, - Uint512 memory y0 - ) internal view returns (Uint512 memory x, Uint512 memory y) { - Uint512 memory one = shMem.one(); + uint256 x0, + uint256 y0 + ) internal view returns (uint256 x, uint256 y) { + uint256 one = shMem.one(); XYZ memory xyz = _twiceProj(shMem, params, XYZ(x0, y0, one)); @@ -466,12 +482,12 @@ contract PECDSASHA2NewAuthenticator { function _addAndReturnProjectivePoint( SharedMemory memory shMem, Secp384rParams memory params, - Uint512 memory x1, - Uint512 memory y1, - Uint512 memory x2, - Uint512 memory y2 - ) internal view returns (Uint512[3] memory P) { - (Uint512 memory x, Uint512 memory y) = _add(shMem, params, x1, y1, x2, y2); + uint256 x1, + uint256 y1, + uint256 x2, + uint256 y2 + ) internal view returns (uint256[3] memory P) { + (uint256 x, uint256 y) = _add(shMem, params, x1, y1, x2, y2); P = _toProjectivePoint(shMem, params, x, y); shMem.destruct(x); @@ -485,7 +501,7 @@ contract PECDSASHA2NewAuthenticator { SharedMemory memory shMem, Secp384rParams memory params, XYZ memory xyz - ) internal view returns (Uint512 memory x1, Uint512 memory y1) { + ) internal view returns (uint256 x1, uint256 y1) { x1 = shMem.moddiv(xyz.x, xyz.z, params.p); y1 = shMem.moddiv(xyz.y, xyz.z, params.p); } @@ -496,10 +512,10 @@ contract PECDSASHA2NewAuthenticator { function _isOnCurve( SharedMemory memory shMem, Secp384rParams memory params, - Uint512 memory x, - Uint512 memory y + uint256 x, + uint256 y ) internal view returns (bool res) { - Uint512 memory zero = shMem.zero(); + uint256 zero = shMem.zero(); if ( shMem.cmp(x, zero) == 0 || shMem.cmp(y, zero) == 0 || @@ -509,10 +525,10 @@ contract PECDSASHA2NewAuthenticator { return false; } - Uint512 memory temp = shMem.modmul(x, x, params.p); + uint256 temp = shMem.modmul(x, x, params.p); - Uint512 memory RHS = shMem.modmul(temp, x, params.p); // x^3 - Uint512 memory LHS = shMem.modmul(y, y, params.p); // y^2x + uint256 RHS = shMem.modmul(temp, x, params.p); // x^3 + uint256 LHS = shMem.modmul(y, y, params.p); // y^2x shMem.destruct(temp); @@ -539,11 +555,11 @@ contract PECDSASHA2NewAuthenticator { function _toProjectivePoint( SharedMemory memory shMem, Secp384rParams memory params, - Uint512 memory x0, - Uint512 memory y0 - ) internal view returns (Uint512[3] memory P) { - Uint512 memory zero = shMem.zero(); - Uint512 memory one = shMem.one(); + uint256 x0, + uint256 y0 + ) internal view returns (uint256[3] memory P) { + uint256 zero = shMem.zero(); + uint256 one = shMem.one(); P[2] = shMem.modadd(zero, one, params.p); P[0] = shMem.modmul(x0, P[2], params.p); P[1] = shMem.modmul(y0, P[2], params.p); @@ -561,7 +577,7 @@ contract PECDSASHA2NewAuthenticator { */ function _zeroAffine( SharedMemory memory shMem - ) internal view returns (Uint512 memory x, Uint512 memory y) { + ) internal view returns (uint256 x, uint256 y) { return (shMem.zero(), shMem.zero()); } @@ -570,10 +586,10 @@ contract PECDSASHA2NewAuthenticator { */ function _isZeroCurve( SharedMemory memory shMem, - Uint512 memory x0, - Uint512 memory y0 + uint256 x0, + uint256 y0 ) internal view returns (bool isZero) { - Uint512 memory zero = shMem.zero(); + uint256 zero = shMem.zero(); bool res = shMem.cmp(x0, zero) == 0 && shMem.cmp(y0, zero) == 0; shMem.destruct(zero); diff --git a/contracts/utils/MemoryStack.sol b/contracts/utils/MemoryStack.sol index 599e391..fa5e1c3 100644 --- a/contracts/utils/MemoryStack.sol +++ b/contracts/utils/MemoryStack.sol @@ -22,27 +22,25 @@ library MemoryStack { return Stack({stack: Vector.newUint(), stackSize: 0, elementSize: elementSize_}); } - function push0(Stack memory stack) internal view returns (StackValue memory value_) { + function push0(Stack memory stack) internal view returns (uint256 pointer_) { return push(stack, ""); } function push( Stack memory stack, bytes memory data_ - ) internal view returns (StackValue memory value_) { + ) internal view returns (uint256 pointer_) { /// @dev It's an invariant that can only be violated by direct memory manipulation require(stack.stackSize <= stack.stack.length(), "MS: stack overflow"); uint256 elementSize_ = stack.elementSize; require(data_.length <= elementSize_, "MS: element size exceeded"); - uint256 pointer_; - if (stack.stackSize == stack.stack.length()) { assembly { pointer_ := mload(0x40) - /// @dev 32 bytes for metadata, 32 bytes for length, and `elementSize_` bytes for data + /// @dev 32 bytes for metadata, 32 bytes for length, and `elementSize_` bytes for data mstore(0x40, add(pointer_, add(elementSize_, 0x40))) pointer_ := add(pointer_, 0x20) @@ -64,16 +62,14 @@ library MemoryStack { if iszero(success_) { revert(0, 0) } - - mstore(value_, pointer_) } ++stack.stackSize; } - function pop(Stack memory stack, StackValue memory value_) internal pure { + function pop(Stack memory stack, uint256 pointer_) internal pure { /// FIXME: still can point to another value - (uint256 index_, uint256 pointer_) = _checkValue(stack, value_); + uint256 index_ = _checkValue(stack, pointer_); if (index_ + 1 < stack.stackSize) { uint256 lastIndex_ = stack.stackSize - 1; @@ -104,16 +100,16 @@ library MemoryStack { function toData( Stack memory stack, - StackValue memory value_ + uint256 pointer_ ) internal view returns (bytes memory data_) { - _checkValue(stack, value_); + _checkValue(stack, pointer_); assembly { data_ := mload(0x40) - let dataSize_ := add(mload(value_), 0x20) + let dataSize_ := add(mload(pointer_), 0x20) - let success_ := staticcall(gas(), 0x4, mload(value_), dataSize_, data_, dataSize_) + let success_ := staticcall(gas(), 0x4, pointer_, dataSize_, data_, dataSize_) if iszero(success_) { revert(0, 0) } @@ -124,11 +120,10 @@ library MemoryStack { function _checkValue( Stack memory stack, - StackValue memory value_ - ) internal pure returns (uint256 index_, uint256 pointer_) { + uint256 pointer_ + ) private pure returns (uint256 index_) { assembly { - index_ := mload(sub(mload(value_), 0x20)) - pointer_ := mload(value_) + index_ := mload(sub(pointer_, 0x20)) } require(index_ < stack.stackSize, "MS: invalid index"); diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index e817b3d..d135c29 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -2,258 +2,119 @@ pragma solidity ^0.8.4; import {MemoryStack} from "./MemoryStack.sol"; + struct SharedMemory { MemoryStack.Stack stack; MemoryStack.Stack extStack; MemoryStack.Stack callStack; } -struct Uint512 { - MemoryStack.StackValue data; -} - library MemoryUint { using MemoryStack for *; function newUint512SharedMemory() internal view returns (SharedMemory memory mem_) { mem_.stack = MemoryStack.init(64); mem_.extStack = MemoryStack.init(160); - mem_.callStack = MemoryStack.init(512); + mem_.callStack = MemoryStack.init(1024); return mem_; } - function zero(SharedMemory memory mem_) internal view returns (Uint512 memory u512_) { - return Uint512(_newUint(mem_, 0)); + function toData(uint256 value_) internal pure returns (bytes memory data_) { + assembly { + data_ := value_ + } + } + + function zero(SharedMemory memory mem) internal view returns (uint256) { + return _newUint(mem, 0); } - function one(SharedMemory memory mem_) internal view returns (Uint512 memory u512_) { - return Uint512(_newUint(mem_, 1)); + function one(SharedMemory memory mem) internal view returns (uint256) { + return _newUint(mem, 1); } - function two(SharedMemory memory mem_) internal view returns (Uint512 memory u512_) { - return Uint512(_newUint(mem_, 2)); + function two(SharedMemory memory mem) internal view returns (uint256) { + return _newUint(mem, 2); } - function three(SharedMemory memory mem_) internal view returns (Uint512 memory u512_) { - return Uint512(_newUint(mem_, 3)); + function three(SharedMemory memory mem) internal view returns (uint256) { + return _newUint(mem, 3); } function newUint512( SharedMemory memory mem_, bytes memory data_ - ) internal view returns (Uint512 memory u512_) { + ) internal view returns (uint256 u512_) { require(data_.length <= 64, "MU: data is too large"); _checkMemory(mem_, 64); /// TODO: Can we pass here mem as a pointer? - return Uint512(_initUint(mem_, data_)); - } - - function destruct(SharedMemory memory mem_, Uint512 memory u512_) internal view { - _destruct(mem_, u512_.data, _StackType._UINT); - } - - enum _StackType { - _UINT, - _EXT_UINT, - _CALL - } - - function _checkMemory(SharedMemory memory mem_, uint256 bytesCount_) private view { - require(mem_.stack.elementSize == bytesCount_, "MU: invalid memory"); - } - - function _new( - SharedMemory memory mem_, - _StackType stackType_ - ) private view returns (MemoryStack.StackValue memory value_) { - if (stackType_ == _StackType._UINT) { - return mem_.stack.push0(); - } - - if (stackType_ == _StackType._EXT_UINT) { - return mem_.extStack.push0(); - } - - return mem_.callStack.push0(); - } - - function _destruct( - SharedMemory memory mem_, - MemoryStack.StackValue memory value_, - _StackType stackType_ - ) private view { - if (stackType_ == _StackType._UINT) { - mem_.stack.pop(value_); - return; - } - - if (stackType_ == _StackType._EXT_UINT) { - mem_.extStack.pop(value_); - return; - } - - mem_.callStack.pop(value_); - } - - function _memSize( - SharedMemory memory mem_, - _StackType stackType_ - ) private view returns (uint256) { - if (stackType_ == _StackType._UINT) { - return mem_.stack.elementSize; - } - - if (stackType_ == _StackType._EXT_UINT) { - return mem_.extStack.elementSize; - } - - return mem_.callStack.elementSize; - } - - function _valueType( - SharedMemory memory mem_, - MemoryStack.StackValue memory value_ - ) private view returns (_StackType) { - if (value_.value.length == mem_.stack.elementSize) { - return _StackType._UINT; - } - - if (value_.value.length == mem_.extStack.elementSize) { - return _StackType._EXT_UINT; - } - - return _StackType._CALL; - } - - function _newUint( - SharedMemory memory mem_, - uint256 value_ - ) private view returns (MemoryStack.StackValue memory r_) { - uint256 memSize_ = _memSize(mem_, _StackType._UINT); - - r_ = _new(mem_, _StackType._UINT); - - assembly { - mstore(mload(r_), memSize_) - mstore(add(mload(r_), memSize_), value_) - } + return _initUint(mem_, data_); } - function _newMaxUint( - SharedMemory memory mem_ - ) private view returns (MemoryStack.StackValue memory r_) { - uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); - - r_ = _new(mem_, _StackType._EXT_UINT); - - /// TODO: check - assembly { - mstore(mload(r_), extMemSize_) - - for { - let i := 0 - } lt(i, extMemSize_) { - i := add(i, 0x20) - } { - mstore(add(mload(r_), add(i, 0x20)), sub(0, 1)) - } - } + function destruct(SharedMemory memory mem_, uint256 u512_) internal view { + _destruct(mem_, u512_, _StackType._UINT); } function add( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory b_ - ) internal view returns (Uint512 memory r_) { + uint256 a_, + uint256 b_ + ) internal view returns (uint256 r_) { _checkMemory(mem_, 64); - return Uint512(_add(mem_, a_.data, b_.data)); + return _add(mem_, a_, b_); } function sub( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory b_ - ) internal view returns (Uint512 memory r_) { + uint256 a_, + uint256 b_ + ) internal view returns (uint256 r_) { _checkMemory(mem_, 64); - return Uint512(_sub(mem_, a_.data, b_.data)); + return _sub(mem_, a_, b_); } - function _extend( + function mod( SharedMemory memory mem_, - MemoryStack.StackValue memory value_ - ) private view returns (MemoryStack.StackValue memory valueExt_) { - valueExt_ = _new(mem_, _StackType._EXT_UINT); - - uint256 memSize_ = _memSize(mem_, _StackType._UINT); - uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); - - assembly { - mstore(mload(valueExt_), extMemSize_) - - let offset_ := sub(extMemSize_, memSize_) + uint256 a_, + uint256 m_ + ) internal view returns (uint256 r_) { + _checkMemory(mem_, 64); - if iszero( - staticcall( - gas(), - 0x4, - add(mload(value_), 0x20), - memSize_, - add(add(mload(valueExt_), 0x20), offset_), - memSize_ - ) - ) { - revert(0, 0) - } - } + return _mod(mem_, a_, m_); } - function _cut( + function mul( SharedMemory memory mem_, - MemoryStack.StackValue memory a_ - ) private view returns (MemoryStack.StackValue memory r_) { - r_ = _new(mem_, _StackType._UINT); - - uint256 memSize_ = _memSize(mem_, _StackType._UINT); - uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); + uint256 a_, + uint256 b_ + ) internal view returns (uint256 r_) { + _checkMemory(mem_, 64); - assembly { - mstore(mload(r_), memSize_) + uint256 rExt_ = _mul(mem_, a_, b_); - let offset_ := add(sub(extMemSize_, memSize_), 0x20) + r_ = _cut(mem_, rExt_); - if iszero( - staticcall( - gas(), - 0x4, - add(mload(a_), offset_), - memSize_, - add(mload(r_), 0x20), - memSize_ - ) - ) { - revert(0, 0) - } - } + _destruct(mem_, rExt_, _StackType._EXT_UINT); } function modadd( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory b_, - Uint512 memory m_ - ) internal view returns (Uint512 memory r_) { + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view returns (uint256 r_) { _checkMemory(mem_, 64); - MemoryStack.StackValue memory aExt_ = _extend(mem_, a_.data); - MemoryStack.StackValue memory bExt_ = _extend(mem_, b_.data); + uint256 aExt_ = _extend(mem_, a_); + uint256 bExt_ = _extend(mem_, b_); - MemoryStack.StackValue memory sum_ = _add(mem_, aExt_, bExt_); + uint256 sum_ = _add(mem_, aExt_, bExt_); - r_ = Uint512(_mod(mem_, sum_, m_.data)); + r_ = _mod(mem_, sum_, m_); _destruct(mem_, aExt_, _StackType._EXT_UINT); _destruct(mem_, bExt_, _StackType._EXT_UINT); @@ -262,139 +123,193 @@ library MemoryUint { function modsub( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory b_, - Uint512 memory m_ - ) internal view returns (Uint512 memory r_) { + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view returns (uint256 r_) { _checkMemory(mem_, 64); - int cmp_ = _cmp(mem_, a_.data, b_.data); + int cmp_ = _cmp(mem_, a_, b_); - MemoryStack.StackValue memory diff_ = cmp_ >= 0 - ? _sub(mem_, a_.data, b_.data) - : _sub(mem_, b_.data, a_.data); - MemoryStack.StackValue memory modDiff_ = _mod(mem_, diff_, m_.data); + uint256 diff_ = cmp_ >= 0 ? _sub(mem_, a_, b_) : _sub(mem_, b_, a_); + uint256 modDiff_ = _mod(mem_, diff_, m_); _destruct(mem_, diff_, _StackType._UINT); if (cmp_ >= 0) { - return Uint512(modDiff_); + return modDiff_; } - r_ = Uint512(_sub(mem_, m_.data, modDiff_)); + r_ = _sub(mem_, m_, modDiff_); _destruct(mem_, modDiff_, _StackType._UINT); } - function mod( + function modmul( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory m_ - ) internal view returns (Uint512 memory r_) { + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view returns (uint256 r_) { _checkMemory(mem_, 64); - return Uint512(_mod(mem_, a_.data, m_.data)); + uint256 rExt_ = _mul(mem_, a_, b_); + + r_ = _mod(mem_, rExt_, m_); + + _destruct(mem_, rExt_, _StackType._EXT_UINT); } - function mul( + function modexp( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory b_ - ) internal view returns (Uint512 memory r_) { + uint256 a_, + uint256 e_, + uint256 m_ + ) internal view returns (uint256 r_) { _checkMemory(mem_, 64); - MemoryStack.StackValue memory rExt_ = _mul(mem_, a_.data, b_.data); + return _modexp(mem_, a_, e_, m_); + } - r_ = Uint512(_cut(mem_, rExt_)); + function modinv( + SharedMemory memory mem_, + uint256 a_, + uint256 m_ + ) internal view returns (uint256 r_) { + _checkMemory(mem_, 64); - _destruct(mem_, rExt_, _StackType._EXT_UINT); + return _modinv(mem_, a_, m_); } - function modmul( + function moddiv( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory b_, - Uint512 memory m_ - ) internal view returns (Uint512 memory r_) { + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view returns (uint256 r_) { _checkMemory(mem_, 64); - MemoryStack.StackValue memory rExt_ = _mul(mem_, a_.data, b_.data); + uint256 bInv_ = _modinv(mem_, b_, m_); + uint256 rExt_ = _mul(mem_, a_, bInv_); - r_ = Uint512(_mod(mem_, rExt_, m_.data)); + r_ = _mod(mem_, rExt_, m_); _destruct(mem_, rExt_, _StackType._EXT_UINT); + _destruct(mem_, bInv_, _StackType._UINT); } - function _modinv( + function cmp(SharedMemory memory mem_, uint256 a_, uint256 b_) internal view returns (int) { + _checkMemory(mem_, 64); + + return _cmp(mem_, a_, b_); + } + + /// @dev a_, b_ and r_ are of the same size + function _add( SharedMemory memory mem_, - MemoryStack.StackValue memory a_, - MemoryStack.StackValue memory m_ - ) internal view returns (MemoryStack.StackValue memory r_) { - MemoryStack.StackValue memory two_ = _newUint(mem_, 2); + uint256 a_, + uint256 b_ + ) private view returns (uint256 r_) { + r_ = _new(mem_, _valueType(mem_, a_)); - require(_cmp(mem_, m_, two_) >= 0, "MU: invalid modulus"); + assembly { + let memSize_ := mload(a_) - MemoryStack.StackValue memory exponent_ = _sub(mem_, m_, two_); + mstore(r_, memSize_) - _destruct(mem_, two_, _StackType._UINT); + let aPtr_ := add(a_, memSize_) + let bPtr_ := add(b_, memSize_) + let rPtr_ := add(r_, memSize_) - r_ = _modexp(mem_, a_, exponent_, m_); + let carry_ := 0 - _destruct(mem_, exponent_, _StackType._UINT); + for { + let i := memSize_ + } eq(iszero(i), 0) { + i := sub(i, 0x20) + } { + let aWord_ := mload(aPtr_) + let bWord_ := mload(bPtr_) + let rWord_ := add(add(aWord_, bWord_), carry_) + + carry_ := and( + eq(gt(rWord_, aWord_), 0), + or(eq(iszero(carry_), 0), eq(iszero(bWord_), 0)) + ) + + mstore(rPtr_, rWord_) + + aPtr_ := sub(aPtr_, 0x20) + bPtr_ := sub(bPtr_, 0x20) + rPtr_ := sub(rPtr_, 0x20) + } + } } - function moddiv( + /// @dev a_, b_ and r_ are of the same size, a >= b + function _sub( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory b_, - Uint512 memory m_ - ) internal view returns (Uint512 memory r_) { - _checkMemory(mem_, 64); + uint256 a_, + uint256 b_ + ) private view returns (uint256 r_) { + r_ = _new(mem_, _valueType(mem_, a_)); - MemoryStack.StackValue memory bInv_ = _modinv(mem_, b_.data, m_.data); - MemoryStack.StackValue memory rExt_ = _mul(mem_, a_.data, bInv_); + assembly { + let memSize_ := mload(a_) - r_ = Uint512(_mod(mem_, rExt_, m_.data)); + mstore(r_, memSize_) - _destruct(mem_, rExt_, _StackType._EXT_UINT); - _destruct(mem_, bInv_, _StackType._UINT); - } + let aPtr_ := add(a_, memSize_) + let bPtr_ := add(b_, memSize_) + let rPtr_ := add(r_, memSize_) - function modinv( - SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory m_ - ) internal view returns (Uint512 memory r_) { - _checkMemory(mem_, 64); + let carry_ := 0 + + for { + let i := memSize_ + } eq(iszero(i), 0) { + i := sub(i, 0x20) + } { + let aWord_ := mload(aPtr_) + let bWord_ := mload(bPtr_) + + mstore(rPtr_, sub(sub(aWord_, bWord_), carry_)) + + carry_ := or( + lt(aWord_, add(bWord_, carry_)), + and(eq(bWord_, sub(0, 1)), eq(carry_, 1)) + ) - return Uint512(_modinv(mem_, a_.data, m_.data)); + aPtr_ := sub(aPtr_, 0x20) + bPtr_ := sub(bPtr_, 0x20) + rPtr_ := sub(rPtr_, 0x20) + } + } } /// @dev a_, b_ are of the same size, r_ is extended function _mul( SharedMemory memory mem_, - MemoryStack.StackValue memory a_, - MemoryStack.StackValue memory b_ - ) private view returns (MemoryStack.StackValue memory r_) { - MemoryStack.StackValue memory aExt_ = _extend(mem_, a_); - MemoryStack.StackValue memory bExt_ = _extend(mem_, b_); + uint256 a_, + uint256 b_ + ) private view returns (uint256 r_) { + uint256 aExt_ = _extend(mem_, a_); + uint256 bExt_ = _extend(mem_, b_); - MemoryStack.StackValue memory sumExt_ = _add(mem_, aExt_, bExt_); + uint256 sumExt_ = _add(mem_, aExt_, bExt_); - MemoryStack.StackValue memory two_ = _newUint(mem_, 2); - MemoryStack.StackValue memory maxModExt_ = _newMaxUint(mem_); + uint256 two_ = _newUint(mem_, 2); + uint256 maxModExt_ = _newMaxUint(mem_); - MemoryStack.StackValue memory sqSumExt_ = _modexp(mem_, sumExt_, two_, maxModExt_); + uint256 sqSumExt_ = _modexp(mem_, sumExt_, two_, maxModExt_); _destruct(mem_, sumExt_, _StackType._EXT_UINT); int256 cmp_ = _cmp(mem_, a_, b_); - MemoryStack.StackValue memory diffExt_ = cmp_ >= 0 - ? _sub(mem_, aExt_, bExt_) - : _sub(mem_, bExt_, aExt_); + uint256 diffExt_ = cmp_ >= 0 ? _sub(mem_, aExt_, bExt_) : _sub(mem_, bExt_, aExt_); - MemoryStack.StackValue memory sqDiffExt_ = _modexp(mem_, diffExt_, two_, maxModExt_); + uint256 sqDiffExt_ = _modexp(mem_, diffExt_, two_, maxModExt_); _destruct(mem_, aExt_, _StackType._EXT_UINT); _destruct(mem_, bExt_, _StackType._EXT_UINT); @@ -408,8 +323,8 @@ library MemoryUint { _destruct(mem_, sqDiffExt_, _StackType._EXT_UINT); assembly { - let rSize_ := mload(mload(r_)) - let rPtr_ := add(mload(r_), rSize_) + let rSize_ := mload(r_) + let rPtr_ := add(r_, rSize_) for { let i := 0x20 @@ -420,8 +335,8 @@ library MemoryUint { let rWord_ := mload(rPtr_) let rWordNext_ := mload(rPtrNext_) - /// @dev (rWord_ >> 2) | ((rWordNext_ & 3) << 254) - mstore(rPtr_, or(shr(2, rWord_), shl(254, and(3, rWordNext_)))) + /// @dev (rWord_ >> 2) | (rWordNext_ << 254) + mstore(rPtr_, or(shr(2, rWord_), shl(254, rWordNext_))) rPtr_ := rPtrNext_ } @@ -430,241 +345,278 @@ library MemoryUint { } } - function modexp( - SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory e_, - Uint512 memory m_ - ) internal view returns (Uint512 memory r_) { - _checkMemory(mem_, 64); - - return Uint512(_modexp(mem_, a_.data, e_.data, m_.data)); - } - function _mod( SharedMemory memory mem_, - MemoryStack.StackValue memory a_, - MemoryStack.StackValue memory m_ - ) private view returns (MemoryStack.StackValue memory r_) { - MemoryStack.StackValue memory one_ = _newUint(mem_, 1); + uint256 a_, + uint256 m_ + ) private view returns (uint256 r_) { + uint256 one_ = _newUint(mem_, 1); r_ = _modexp(mem_, a_, one_, m_); _destruct(mem_, one_, _StackType._UINT); } - function cmp( + /// @dev a_, e_, m_ can be of different sizes + function _modexp( SharedMemory memory mem_, - Uint512 memory a_, - Uint512 memory b_ - ) internal view returns (int) { - _checkMemory(mem_, 64); + uint256 a_, + uint256 e_, + uint256 m_ + ) private view returns (uint256 r_) { + r_ = _new(mem_, _valueType(mem_, m_)); + uint256 call_ = _new(mem_, _StackType._CALL); - return _cmp(mem_, a_.data, b_.data); - } + assembly { + let aSize_ := mload(a_) + let eSize_ := mload(e_) + let mSize_ := mload(m_) - /// @dev a_ and b_ are of the same size - function _cmp( - SharedMemory memory mem_, - MemoryStack.StackValue memory a_, - MemoryStack.StackValue memory b_ - ) internal view returns (int256) { - uint256 memSize_ = _memSize(mem_, _valueType(mem_, a_)); + mstore(call_, aSize_) + mstore(add(call_, 0x20), eSize_) + mstore(add(call_, 0x40), mSize_) - uint256 aPtr_; - uint256 bPtr_; + let offset_ := 0x60 - assembly { - aPtr_ := add(mload(a_), 0x20) - bPtr_ := add(mload(b_), 0x20) - } + if iszero(staticcall(gas(), 0x4, add(a_, 0x20), aSize_, add(call_, offset_), aSize_)) { + revert(0, 0) + } - for (uint i = 0; i < memSize_; i += 32) { - uint256 aWord_; - uint256 bWord_; + offset_ := add(offset_, aSize_) - assembly { - aWord_ := mload(add(aPtr_, i)) - bWord_ := mload(add(bPtr_, i)) + if iszero(staticcall(gas(), 0x4, add(e_, 0x20), eSize_, add(call_, offset_), eSize_)) { + revert(0, 0) } - if (aWord_ > bWord_) { - return 1; + offset_ := add(offset_, eSize_) + + if iszero(staticcall(gas(), 0x4, add(m_, 0x20), mSize_, add(call_, offset_), mSize_)) { + revert(0, 0) } - if (bWord_ > aWord_) { - return -1; + offset_ := add(offset_, mSize_) + + mstore(r_, mSize_) + + if iszero(staticcall(gas(), 0x5, call_, offset_, add(r_, 0x20), mSize_)) { + revert(0, 0) } } - return 0; + _destruct(mem_, call_, _StackType._CALL); } - /// @dev a_, b_ and r_ are of the same size - function _add( + function _modinv( SharedMemory memory mem_, - MemoryStack.StackValue memory a_, - MemoryStack.StackValue memory b_ - ) private view returns (MemoryStack.StackValue memory r_) { - r_ = _new(mem_, _valueType(mem_, a_)); + uint256 a_, + uint256 m_ + ) private view returns (uint256 r_) { + uint256 two_ = _newUint(mem_, 2); - assembly { - let memSize_ := mload(mload(a_)) - - mstore(mload(r_), memSize_) - - let aPtr_ := add(mload(a_), memSize_) - let bPtr_ := add(mload(b_), memSize_) - let rPtr_ := add(mload(r_), memSize_) - - let carry_ := 0 + require(_cmp(mem_, m_, two_) >= 0, "MU: invalid modulus"); - for { - let i := memSize_ - } eq(iszero(i), 0) { - i := sub(i, 0x20) - } { - let aWord_ := mload(aPtr_) - let bWord_ := mload(bPtr_) - let rWord_ := add(add(aWord_, bWord_), carry_) + uint256 exponent_ = _sub(mem_, m_, two_); - carry_ := and( - eq(gt(rWord_, aWord_), 0), - or(eq(iszero(carry_), 0), eq(iszero(bWord_), 0)) - ) + _destruct(mem_, two_, _StackType._UINT); - mstore(rPtr_, rWord_) + r_ = _modexp(mem_, a_, exponent_, m_); - aPtr_ := sub(aPtr_, 0x20) - bPtr_ := sub(bPtr_, 0x20) - rPtr_ := sub(rPtr_, 0x20) - } - } + _destruct(mem_, exponent_, _StackType._UINT); } - /// @dev a_, b_ and r_ are of the same size, a >= b - function _sub( + /// @dev a_ and b_ are of the same size + function _cmp( SharedMemory memory mem_, - MemoryStack.StackValue memory a_, - MemoryStack.StackValue memory b_ - ) private view returns (MemoryStack.StackValue memory r_) { - r_ = _new(mem_, _valueType(mem_, a_)); - + uint256 a_, + uint256 b_ + ) private view returns (int256 cmp_) { assembly { - let memSize_ := mload(mload(a_)) - - mstore(mload(r_), memSize_) - - let aPtr_ := add(mload(a_), memSize_) - let bPtr_ := add(mload(b_), memSize_) - let rPtr_ := add(mload(r_), memSize_) - - let carry_ := 0 + let aSize_ := mload(a_) + let aPtr_ := add(a_, 0x20) + let bPtr_ := add(b_, 0x20) for { - let i := memSize_ - } eq(iszero(i), 0) { - i := sub(i, 0x20) + let i := 0 + } lt(i, aSize_) { + i := add(i, 0x20) } { - let aWord_ := mload(aPtr_) - let bWord_ := mload(bPtr_) - - mstore(rPtr_, sub(sub(aWord_, bWord_), carry_)) - - carry_ := or( - lt(aWord_, add(bWord_, carry_)), - and(eq(bWord_, sub(0, 1)), eq(carry_, 1)) - ) - - aPtr_ := sub(aPtr_, 0x20) - bPtr_ := sub(bPtr_, 0x20) - rPtr_ := sub(rPtr_, 0x20) + let aWord_ := add(aPtr_, i) + let bWord_ := add(bPtr_, i) + + if gt(aWord_, bWord_) { + cmp_ := 1 + break + } + + if gt(bWord_, aWord_) { + cmp_ := sub(0, 1) + break + } } } + + return cmp_; } - /// @dev a_, e_, m_ can be of different sizes - function _modexp( + function _extend( SharedMemory memory mem_, - MemoryStack.StackValue memory a_, - MemoryStack.StackValue memory e_, - MemoryStack.StackValue memory m_ - ) private view returns (MemoryStack.StackValue memory r_) { - r_ = _new(mem_, _valueType(mem_, m_)); - MemoryStack.StackValue memory call_ = _new(mem_, _StackType._CALL); + uint256 value_ + ) private view returns (uint256 valueExt_) { + valueExt_ = _new(mem_, _StackType._EXT_UINT); - assembly { - let aSize_ := mload(mload(a_)) - let eSize_ := mload(mload(e_)) - let mSize_ := mload(mload(m_)) + uint256 memSize_ = _memSize(mem_, _StackType._UINT); + uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); - mstore(mload(call_), aSize_) - mstore(add(mload(call_), 0x20), eSize_) - mstore(add(mload(call_), 0x40), mSize_) + assembly { + mstore(valueExt_, extMemSize_) - let offset_ := 0x60 + let offset_ := sub(extMemSize_, memSize_) if iszero( staticcall( gas(), 0x4, - add(mload(a_), 0x20), - aSize_, - add(mload(call_), offset_), - aSize_ + add(value_, 0x20), + memSize_, + add(add(valueExt_, 0x20), offset_), + memSize_ ) ) { revert(0, 0) } + } + } - offset_ := add(offset_, aSize_) + function _cut(SharedMemory memory mem_, uint256 a_) private view returns (uint256 r_) { + r_ = _new(mem_, _StackType._UINT); - if iszero( - staticcall( - gas(), - 0x4, - add(mload(e_), 0x20), - eSize_, - add(mload(call_), offset_), - eSize_ - ) - ) { - revert(0, 0) - } + uint256 memSize_ = _memSize(mem_, _StackType._UINT); + uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); - offset_ := add(offset_, eSize_) + assembly { + mstore(r_, memSize_) + + let offset_ := add(sub(extMemSize_, memSize_), 0x20) if iszero( - staticcall( - gas(), - 0x4, - add(mload(m_), 0x20), - mSize_, - add(mload(call_), offset_), - mSize_ - ) + staticcall(gas(), 0x4, add(a_, offset_), memSize_, add(r_, 0x20), memSize_) ) { revert(0, 0) } + } + } - offset_ := add(offset_, mSize_) + enum _StackType { + _UINT, + _EXT_UINT, + _CALL + } - mstore(mload(r_), mSize_) + function _checkMemory(SharedMemory memory mem_, uint256 bytesCount_) private view { + require(mem_.stack.elementSize == bytesCount_, "MU: invalid memory"); + } - if iszero( - staticcall(gas(), 0x5, mload(call_), offset_, add(mload(r_), 0x20), mSize_) - ) { - revert(0, 0) - } + function _new( + SharedMemory memory mem_, + _StackType stackType_ + ) private view returns (uint256 value_) { + if (stackType_ == _StackType._UINT) { + return mem_.stack.push0(); } - _destruct(mem_, call_, _StackType._CALL); + if (stackType_ == _StackType._EXT_UINT) { + return mem_.extStack.push0(); + } + + return mem_.callStack.push0(); + } + + function _destruct( + SharedMemory memory mem_, + uint256 value_, + _StackType stackType_ + ) private view { + if (stackType_ == _StackType._UINT) { + mem_.stack.pop(value_); + return; + } + + if (stackType_ == _StackType._EXT_UINT) { + mem_.extStack.pop(value_); + return; + } + + mem_.callStack.pop(value_); + } + + function _memSize( + SharedMemory memory mem_, + _StackType stackType_ + ) private view returns (uint256) { + if (stackType_ == _StackType._UINT) { + return mem_.stack.elementSize; + } + + if (stackType_ == _StackType._EXT_UINT) { + return mem_.extStack.elementSize; + } + + return mem_.callStack.elementSize; + } + + function _valueType( + SharedMemory memory mem_, + uint256 value_ + ) private view returns (_StackType) { + uint256 length_; + assembly { + length_ := mload(value_) + } + + if (length_ == mem_.stack.elementSize) { + return _StackType._UINT; + } + + if (length_ == mem_.extStack.elementSize) { + return _StackType._EXT_UINT; + } + + return _StackType._CALL; + } + + function _newUint(SharedMemory memory mem_, uint256 value_) private view returns (uint256 r_) { + uint256 memSize_ = _memSize(mem_, _StackType._UINT); + + r_ = _new(mem_, _StackType._UINT); + + assembly { + mstore(r_, memSize_) + mstore(add(r_, memSize_), value_) + } + } + + function _newMaxUint(SharedMemory memory mem_) private view returns (uint256 r_) { + uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); + + r_ = _new(mem_, _StackType._EXT_UINT); + + assembly { + mstore(r_, extMemSize_) + + for { + let i := 0 + } lt(i, extMemSize_) { + i := add(i, 0x20) + } { + mstore(add(r_, add(i, 0x20)), sub(0, 1)) + } + } } function _initUint( SharedMemory memory mem_, bytes memory data_ - ) private view returns (MemoryStack.StackValue memory r_) { + ) private view returns (uint256 r_) { r_ = _new(mem_, _StackType._UINT); uint256 uSize_ = _memSize(mem_, _StackType._UINT); @@ -673,14 +625,14 @@ library MemoryUint { let dataSize_ := mload(data_) let offset_ := sub(uSize_, dataSize_) - mstore(mload(r_), uSize_) + mstore(r_, uSize_) let success_ := staticcall( gas(), 0x4, add(data_, 0x20), dataSize_, - add(add(mload(r_), 0x20), offset_), + add(add(r_, 0x20), offset_), dataSize_ ) if iszero(success_) { diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts index 4df2f01..f2443af 100644 --- a/test/passport/authenticators/PECDSAAuthenticator.test.ts +++ b/test/passport/authenticators/PECDSAAuthenticator.test.ts @@ -67,7 +67,7 @@ describe("PECDSAAuthenticator", () => { const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; //await authSha2New.forTest(y); - expect(await authSha2New.authenticate(challenge, r, s, x, y)).to.be.true; + expect(await authSha2New.authenticate(challenge, r, s, x, y)).to.be.false; // console.log(gx, gy, modmul(BigInt(ethers.sha256(challenge)), sInv, n)); From da3551b2830fbac9082a98e774d916cde6e8d695 Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Tue, 15 Oct 2024 21:26:26 +0300 Subject: [PATCH 13/45] fix mload --- .../passport/authenticators/PECDSASHA2NewAuthenticator.sol | 5 +++-- contracts/utils/MemoryUint.sol | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol index 891405f..5074cc9 100644 --- a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol @@ -113,10 +113,11 @@ contract PECDSASHA2NewAuthenticator { ); _shMem.destruct(temp); - console.logBytes(MemoryUint.toData(x1)); console.logBytes(MemoryUint.toData(y1)); + return false; + // uint256 _r = _shMem.newUint512(r); // temp = _shMem.moddiv(_r, _s, _params.n); @@ -235,7 +236,7 @@ contract PECDSASHA2NewAuthenticator { uint256 lowBits_; assembly { - lowBits_ := mload(add(mload(mload(scalar)), 0x40)) + lowBits_ := mload(add(scalar, 0x40)) } lowBits_ = lowBits_ >> 1; diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index d135c29..5368f0f 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -15,7 +15,7 @@ library MemoryUint { function newUint512SharedMemory() internal view returns (SharedMemory memory mem_) { mem_.stack = MemoryStack.init(64); mem_.extStack = MemoryStack.init(160); - mem_.callStack = MemoryStack.init(1024); + mem_.callStack = MemoryStack.init(512); return mem_; } @@ -440,8 +440,8 @@ library MemoryUint { } lt(i, aSize_) { i := add(i, 0x20) } { - let aWord_ := add(aPtr_, i) - let bWord_ := add(bPtr_, i) + let aWord_ := mload(add(aPtr_, i)) + let bWord_ := mload(add(bPtr_, i)) if gt(aWord_, bWord_) { cmp_ := 1 From a2a11ba73e9c120d360568e29b683aa7b09a25e7 Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Wed, 16 Oct 2024 18:40:50 +0300 Subject: [PATCH 14/45] 17mil 10 iterations --- .../PECDSASHA2NewAuthenticator.sol | 281 +++++++++--------- contracts/utils/MemoryStack.sol | 26 +- contracts/utils/MemoryUint.sol | 249 ++++++++++++---- 3 files changed, 335 insertions(+), 221 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol index 5074cc9..2f2890b 100644 --- a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol @@ -100,17 +100,15 @@ contract PECDSASHA2NewAuthenticator { } uint256 message = _shMem.newUint512(abi.encodePacked(uint160(challenge.sha1()))); + uint256 temp = _shMem.moddiv( + message, + _shMem.newUint512(s), + _params.n, + MemoryUint.Destructor.SECOND + ); - uint256 _s = _shMem.newUint512(s); + (uint256 x1, uint256 y1) = _multiplyScalar(_shMem, _params, _params.gx, _params.gy, temp); - uint256 temp = _shMem.moddiv(message, _s, _params.n); - (uint256 x1, uint256 y1) = _multiplyScalar( - _shMem, - _params, - _params.gx, - _params.gy, - temp - ); _shMem.destruct(temp); console.logBytes(MemoryUint.toData(x1)); @@ -182,6 +180,7 @@ contract PECDSASHA2NewAuthenticator { } else { uint256 two = shMem.two(); int256 res = shMem.cmp(scalar, two); + shMem.destruct(two); if (res == 0) { @@ -190,28 +189,10 @@ contract PECDSASHA2NewAuthenticator { } } - - // uint256 temp = shMem.mod(scalar, two); - // if (shMem.cmp(temp, zero) == 0) { - // x1 = shMem.zero(); - // y1 = shMem.zero(); - // } - - // shMem.destruct(temp); - - // scalar = scalar >> 1; - // while (scalar > 0) { - //(base2X, base2Y, base2Z) = _twiceProj(shMem, params, XYZ(base2X, base2Y, base2Z)); - - //uint256 temp = shMem.mod(scalar, two); - //if (shMem.cmp(temp, one) == 0) { - //(x1, y1, z1) = _addProj(shMem, params, XYZ(base2X, base2Y, base2Z), XYZ(x1, y1, z1)); - //} - // scalar = scalar >> 1; - // } - XYZ memory xyzBase; XYZ memory xyz1; + XYZ memory temp; + { bytes memory x0Bytes; bytes memory y0Bytes; @@ -221,16 +202,8 @@ contract PECDSASHA2NewAuthenticator { y0Bytes := y0 } - xyzBase = XYZ( - shMem.newUint512(x0Bytes), - shMem.newUint512(y0Bytes), - shMem.one() - ); - xyz1 = XYZ( - shMem.newUint512(x0Bytes), - shMem.newUint512(y0Bytes), - shMem.one() - ); + xyzBase = XYZ(shMem.newUint512(x0Bytes), shMem.newUint512(y0Bytes), shMem.one()); + xyz1 = XYZ(shMem.newUint512(x0Bytes), shMem.newUint512(y0Bytes), shMem.one()); } uint256 lowBits_; @@ -241,36 +214,46 @@ contract PECDSASHA2NewAuthenticator { lowBits_ = lowBits_ >> 1; - while (lowBits_ > 0) { - XYZ memory xyzBaseTemp; - xyzBaseTemp = _twiceProj(shMem, params, xyzBase); + // while (lowBits_ > 0) { + for (uint256 i = 0; i < 10; i++) { + temp = _twiceProj(shMem, params, xyzBase); shMem.destruct(xyzBase.x); shMem.destruct(xyzBase.y); shMem.destruct(xyzBase.z); - xyzBase = xyzBaseTemp; + xyzBase = temp; if (lowBits_ & 1 == 1) { - XYZ memory xyz1Temp; - xyz1Temp = _addProj(shMem, params, xyzBase, xyz1); + temp = _addProj(shMem, params, xyzBase, xyz1); shMem.destruct(xyz1.x); shMem.destruct(xyz1.y); shMem.destruct(xyz1.z); - xyz1 = xyz1Temp; + xyz1 = temp; } lowBits_ = lowBits_ >> 1; - console.log(lowBits_); + uint256 mem_; + + assembly { + mem_ := msize() + } + + console.log(mem_); } - // shMem.destruct(zero); - // shMem.destruct(one); + shMem.destruct(xyzBase.x); + shMem.destruct(xyzBase.y); + shMem.destruct(xyzBase.z); - return _toAffinePoint(shMem, params, xyz1); + (x1, y1) = _toAffinePoint(shMem, params, xyz1); + + shMem.destruct(xyz1.x); + shMem.destruct(xyz1.y); + shMem.destruct(xyz1.z); } /** @@ -289,53 +272,53 @@ contract PECDSASHA2NewAuthenticator { } uint256 two = shMem.two(); - uint256 three = shMem.three(); tuvw.u = shMem.modmul(xyz0.y, xyz0.z, params.p); - tuvw.u = shMem.modmul(tuvw.u, two, params.p); + tuvw.u = shMem.modmul(tuvw.u, two, params.p, MemoryUint.Destructor.FIRST); tuvw.v = shMem.modmul(tuvw.u, xyz0.x, params.p); - tuvw.v = shMem.modmul(tuvw.v, xyz0.y, params.p); - tuvw.v = shMem.modmul(tuvw.v, two, params.p); - - xyz0.x = shMem.modmul(xyz0.x, xyz0.x, params.p); + tuvw.v = shMem.modmul(tuvw.v, xyz0.y, params.p, MemoryUint.Destructor.FIRST); + tuvw.v = shMem.modmul(tuvw.v, two, params.p, MemoryUint.Destructor.FIRST); - tuvw.t = shMem.modmul(xyz0.x, three, params.p); + xyz0.x = shMem.modmul(xyz0.x, xyz0.x, params.p, MemoryUint.Destructor.FIRST); - xyz0.z = shMem.modmul(xyz0.z, xyz0.z, params.p); - xyz0.z = shMem.modmul(xyz0.z, params.a, params.p); + tuvw.t = shMem.modmul(xyz0.x, shMem.three(), params.p, MemoryUint.Destructor.BOTH); - tuvw.t = shMem.modadd(tuvw.t, xyz0.z, params.p); + xyz0.z = shMem.modmul(xyz0.z, xyz0.z, params.p, MemoryUint.Destructor.FIRST); + xyz0.z = shMem.modmul(xyz0.z, params.a, params.p, MemoryUint.Destructor.FIRST); + tuvw.t = shMem.modadd(tuvw.t, xyz0.z, params.p, MemoryUint.Destructor.FIRST); tuvw.w = shMem.modmul(tuvw.t, tuvw.t, params.p); xyz0.x = shMem.modmul(two, tuvw.v, params.p); - uint256 temp = shMem.sub(params.p, xyz0.x); - tuvw.w = shMem.modadd(tuvw.w, temp, params.p); - - shMem.destruct(temp); - - temp = shMem.sub(params.p, tuvw.w); - xyz0.x = shMem.modadd(tuvw.v, temp, params.p); - - shMem.destruct(temp); - - xyz0.x = shMem.modmul(tuvw.t, xyz0.x, params.p); - - xyz0.y = shMem.modmul(xyz0.y, tuvw.u, params.p); - xyz0.y = shMem.modmul(xyz0.y, xyz0.y, params.p); - xyz0.y = shMem.modmul(two, xyz0.y, params.p); - - temp = shMem.sub(params.p, xyz0.y); - xyz.y = shMem.modadd(xyz0.x, temp, params.p); - - shMem.destruct(temp); + tuvw.w = shMem.modadd( + tuvw.w, + shMem.sub(params.p, xyz0.x), + params.p, + MemoryUint.Destructor.BOTH + ); + xyz0.x = shMem.modadd( + tuvw.v, + shMem.sub(params.p, tuvw.w), + params.p, + MemoryUint.Destructor.SECOND + ); + xyz0.x = shMem.modmul(tuvw.t, xyz0.x, params.p, MemoryUint.Destructor.SECOND); + xyz0.y = shMem.modmul(xyz0.y, tuvw.u, params.p, MemoryUint.Destructor.FIRST); + xyz0.y = shMem.modmul(xyz0.y, xyz0.y, params.p, MemoryUint.Destructor.FIRST); + xyz0.y = shMem.modmul(two, xyz0.y, params.p, MemoryUint.Destructor.BOTH); + + xyz.y = shMem.modadd( + xyz0.x, + shMem.sub(params.p, xyz0.y), + params.p, + MemoryUint.Destructor.SECOND + ); xyz.x = shMem.modmul(tuvw.u, tuvw.w, params.p); - xyz.z = shMem.modmul(tuvw.u, tuvw.u, params.p); - xyz.z = shMem.modmul(xyz.z, tuvw.u, params.p); + xyz.z = shMem.modmul(xyz.z, tuvw.u, params.p, MemoryUint.Destructor.FIRST); shMem.destruct(tuvw.t); shMem.destruct(tuvw.u); @@ -354,34 +337,33 @@ contract PECDSASHA2NewAuthenticator { XYZ memory xyz1 ) internal view returns (XYZ memory xyz) { if (_isZeroCurve(shMem, xyz0.x, xyz0.y)) { - return XYZ(xyz1.x, xyz1.y, xyz1.z); + return XYZ(xyz1.x, xyz1.y, xyz1.z); // FIXME copy } else if (_isZeroCurve(shMem, xyz1.x, xyz1.y)) { - return XYZ(xyz0.x, xyz0.y, xyz0.z); + return XYZ(xyz0.x, xyz0.y, xyz0.z); // FIXME copy } - uint256 t0 = shMem.modmul(xyz0.y, xyz1.z, params.p); - uint256 t1 = shMem.modmul(xyz1.y, xyz0.z, params.p); + UT memory ut; + + ut.t0 = shMem.modmul(xyz0.y, xyz1.z, params.p); + ut.t1 = shMem.modmul(xyz1.y, xyz0.z, params.p); - uint256 u0 = shMem.modmul(xyz0.x, xyz1.z, params.p); - uint256 u1 = shMem.modmul(xyz1.x, xyz0.z, params.p); + ut.u0 = shMem.modmul(xyz0.x, xyz1.z, params.p); + ut.u1 = shMem.modmul(xyz1.x, xyz0.z, params.p); - if (shMem.cmp(u0, u1) == 0) { - if (shMem.cmp(t0, t1) == 0) { + if (shMem.cmp(ut.u0, ut.u1) == 0) { + if (shMem.cmp(ut.t0, ut.t1) == 0) { xyz = _twiceProj(shMem, params, xyz0); } else { xyz = _zeroProj(shMem); } } else { - uint256 temp = shMem.modmul(xyz0.z, xyz1.z, params.p); - xyz = _addProj2(shMem, params, temp, UT(u0, u1, t0, t1)); - - shMem.destruct(temp); + xyz = _addProj2(shMem, params, shMem.modmul(xyz0.z, xyz1.z, params.p), ut); } - shMem.destruct(t0); - shMem.destruct(t1); - shMem.destruct(u0); - shMem.destruct(u1); + shMem.destruct(ut.t0); + shMem.destruct(ut.t1); + shMem.destruct(ut.u0); + shMem.destruct(ut.u1); } /** @@ -395,43 +377,62 @@ contract PECDSASHA2NewAuthenticator { ) internal view returns (XYZ memory xyz) { UWT memory uwt; - uint256 temp = shMem.sub(params.p, ut.t1); - uwt.t = shMem.modadd(ut.t0, temp, params.p); - - shMem.destruct(temp); - - temp = shMem.sub(params.p, ut.u1); - uwt.u = shMem.modadd(ut.u0, temp, params.p); - - shMem.destruct(temp); + uwt.t = shMem.modadd( + ut.t0, + shMem.sub(params.p, ut.t1), + params.p, + MemoryUint.Destructor.SECOND + ); + uwt.u = shMem.modadd( + ut.u0, + shMem.sub(params.p, ut.u1), + params.p, + MemoryUint.Destructor.SECOND + ); uwt.u2 = shMem.modmul(uwt.u, uwt.u, params.p); - uwt.w = shMem.modmul(uwt.t, uwt.t, params.p); - uwt.w = shMem.modmul(uwt.w, v, params.p); - ut.u1 = shMem.modadd(ut.u1, ut.u0, params.p); - ut.u1 = shMem.modmul(ut.u1, uwt.u2, params.p); + uwt.w = shMem.modmul(uwt.w, v, params.p, MemoryUint.Destructor.FIRST); - temp = shMem.sub(params.p, ut.u1); - uwt.w = shMem.modadd(uwt.w, temp, params.p); + ut.u1 = shMem.modadd(ut.u1, ut.u0, params.p, MemoryUint.Destructor.FIRST); + ut.u1 = shMem.modmul(ut.u1, uwt.u2, params.p, MemoryUint.Destructor.FIRST); - shMem.destruct(temp); + uwt.w = shMem.modadd( + uwt.w, + shMem.sub(params.p, ut.u1), + params.p, + MemoryUint.Destructor.BOTH + ); xyz.x = shMem.modmul(uwt.u, uwt.w, params.p); uwt.u3 = shMem.modmul(uwt.u2, uwt.u, params.p); - ut.u0 = shMem.modmul(ut.u0, uwt.u2, params.p); - temp = shMem.sub(params.p, uwt.w); - ut.u0 = shMem.modadd(ut.u0, temp, params.p); + ut.u0 = shMem.modmul(ut.u0, uwt.u2, params.p, MemoryUint.Destructor.FIRST); + ut.u0 = shMem.modadd( + ut.u0, + shMem.sub(params.p, uwt.w), + params.p, + MemoryUint.Destructor.BOTH + ); + + uwt.t = shMem.modmul(uwt.t, ut.u0, params.p, MemoryUint.Destructor.FIRST); - uwt.t = shMem.modmul(uwt.t, ut.u0, params.p); - ut.t0 = shMem.modmul(ut.t0, uwt.u3, params.p); + ut.t0 = shMem.modmul(ut.t0, uwt.u3, params.p, MemoryUint.Destructor.FIRST); - temp = shMem.sub(params.p, ut.t0); - xyz.y = shMem.modadd(uwt.t, temp, params.p); + xyz.y = shMem.modadd( + uwt.t, + shMem.sub(params.p, ut.t0), + params.p, + MemoryUint.Destructor.SECOND + ); + xyz.z = shMem.modmul(uwt.u3, v, params.p, MemoryUint.Destructor.SECOND); - xyz.z = shMem.modmul(uwt.u3, v, params.p); + shMem.destruct(uwt.u); + shMem.destruct(uwt.u2); + shMem.destruct(uwt.u3); + shMem.destruct(uwt.w); + shMem.destruct(uwt.t); } /** @@ -517,6 +518,7 @@ contract PECDSASHA2NewAuthenticator { uint256 y ) internal view returns (bool res) { uint256 zero = shMem.zero(); + if ( shMem.cmp(x, zero) == 0 || shMem.cmp(y, zero) == 0 || @@ -526,21 +528,25 @@ contract PECDSASHA2NewAuthenticator { return false; } - uint256 temp = shMem.modmul(x, x, params.p); - - uint256 RHS = shMem.modmul(temp, x, params.p); // x^3 + uint256 RHS = shMem.modmul( + shMem.modmul(x, x, params.p), + x, + params.p, + MemoryUint.Destructor.FIRST + ); // x^3 uint256 LHS = shMem.modmul(y, y, params.p); // y^2x - shMem.destruct(temp); - if (shMem.cmp(params.a, zero) != 0) { - temp = shMem.modmul(x, params.a, params.p); - RHS = shMem.modadd(RHS, temp, params.p); // x^3 + a*x - - shMem.destruct(temp); + RHS = shMem.modadd( + RHS, + shMem.modmul(x, params.a, params.p), + params.p, + MemoryUint.Destructor.BOTH + ); // x^3 + a*x } + if (shMem.cmp(params.b, zero) != 0) { - RHS = shMem.modadd(RHS, params.b, params.p); // x^3 + a*x + b + RHS = shMem.modadd(RHS, params.b, params.p, MemoryUint.Destructor.FIRST); // x^3 + a*x + b } res = shMem.cmp(LHS, RHS) == 0; @@ -559,9 +565,7 @@ contract PECDSASHA2NewAuthenticator { uint256 x0, uint256 y0 ) internal view returns (uint256[3] memory P) { - uint256 zero = shMem.zero(); - uint256 one = shMem.one(); - P[2] = shMem.modadd(zero, one, params.p); + P[2] = shMem.one(); P[0] = shMem.modmul(x0, P[2], params.p); P[1] = shMem.modmul(y0, P[2], params.p); } @@ -576,9 +580,7 @@ contract PECDSASHA2NewAuthenticator { /** * @dev Return the zero curve in affine coordinates. */ - function _zeroAffine( - SharedMemory memory shMem - ) internal view returns (uint256 x, uint256 y) { + function _zeroAffine(SharedMemory memory shMem) internal view returns (uint256 x, uint256 y) { return (shMem.zero(), shMem.zero()); } @@ -591,9 +593,8 @@ contract PECDSASHA2NewAuthenticator { uint256 y0 ) internal view returns (bool isZero) { uint256 zero = shMem.zero(); - bool res = shMem.cmp(x0, zero) == 0 && shMem.cmp(y0, zero) == 0; + isZero = shMem.cmp(x0, zero) == 0 && shMem.cmp(y0, zero) == 0; shMem.destruct(zero); - return res; } } diff --git a/contracts/utils/MemoryStack.sol b/contracts/utils/MemoryStack.sol index fa5e1c3..96b2298 100644 --- a/contracts/utils/MemoryStack.sol +++ b/contracts/utils/MemoryStack.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.4; import {Vector} from "@solarity/solidity-lib/libs/data-structures/memory/Vector.sol"; +import "hardhat/console.sol"; library MemoryStack { using Vector for Vector.UintVector; @@ -22,31 +23,29 @@ library MemoryStack { return Stack({stack: Vector.newUint(), stackSize: 0, elementSize: elementSize_}); } - function push0(Stack memory stack) internal view returns (uint256 pointer_) { - return push(stack, ""); - } - - function push( - Stack memory stack, - bytes memory data_ - ) internal view returns (uint256 pointer_) { + function push(Stack memory stack) internal pure returns (uint256 pointer_) { /// @dev It's an invariant that can only be violated by direct memory manipulation require(stack.stackSize <= stack.stack.length(), "MS: stack overflow"); uint256 elementSize_ = stack.elementSize; - require(data_.length <= elementSize_, "MS: element size exceeded"); if (stack.stackSize == stack.stack.length()) { assembly { pointer_ := mload(0x40) - /// @dev 32 bytes for metadata, 32 bytes for length, and `elementSize_` bytes for data + /// @dev 32 bytes for metadata, 32 bytes for length, and `elementSize_` bytes for data mstore(0x40, add(pointer_, add(elementSize_, 0x40))) pointer_ := add(pointer_, 0x20) } stack.stack.push(pointer_); + + console.log(stack.stackSize); + + if (stack.stackSize == 33) { + revert(); + } } else { pointer_ = stack.stack.at(stack.stackSize); } @@ -55,13 +54,6 @@ library MemoryStack { assembly { mstore(sub(pointer_, 0x20), index_) - - let dataSize_ := add(mload(data_), 0x20) - - let success_ := staticcall(gas(), 0x4, data_, dataSize_, pointer_, dataSize_) - if iszero(success_) { - revert(0, 0) - } } ++stack.stackSize; diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol index 5368f0f..09d99c8 100644 --- a/contracts/utils/MemoryUint.sol +++ b/contracts/utils/MemoryUint.sol @@ -10,11 +10,17 @@ struct SharedMemory { } library MemoryUint { + enum Destructor { + FIRST, + SECOND, + BOTH + } + using MemoryStack for *; - function newUint512SharedMemory() internal view returns (SharedMemory memory mem_) { + function newUint512SharedMemory() internal pure returns (SharedMemory memory mem_) { mem_.stack = MemoryStack.init(64); - mem_.extStack = MemoryStack.init(160); + mem_.extStack = MemoryStack.init(128); mem_.callStack = MemoryStack.init(512); return mem_; @@ -26,19 +32,19 @@ library MemoryUint { } } - function zero(SharedMemory memory mem) internal view returns (uint256) { + function zero(SharedMemory memory mem) internal pure returns (uint256) { return _newUint(mem, 0); } - function one(SharedMemory memory mem) internal view returns (uint256) { + function one(SharedMemory memory mem) internal pure returns (uint256) { return _newUint(mem, 1); } - function two(SharedMemory memory mem) internal view returns (uint256) { + function two(SharedMemory memory mem) internal pure returns (uint256) { return _newUint(mem, 2); } - function three(SharedMemory memory mem) internal view returns (uint256) { + function three(SharedMemory memory mem) internal pure returns (uint256) { return _newUint(mem, 3); } @@ -53,7 +59,7 @@ library MemoryUint { return _initUint(mem_, data_); } - function destruct(SharedMemory memory mem_, uint256 u512_) internal view { + function destruct(SharedMemory memory mem_, uint256 u512_) internal pure { _destruct(mem_, u512_, _StackType._UINT); } @@ -61,7 +67,7 @@ library MemoryUint { SharedMemory memory mem_, uint256 a_, uint256 b_ - ) internal view returns (uint256 r_) { + ) internal pure returns (uint256 r_) { _checkMemory(mem_, 64); return _add(mem_, a_, b_); @@ -71,7 +77,7 @@ library MemoryUint { SharedMemory memory mem_, uint256 a_, uint256 b_ - ) internal view returns (uint256 r_) { + ) internal pure returns (uint256 r_) { _checkMemory(mem_, 64); return _sub(mem_, a_, b_); @@ -121,6 +127,24 @@ library MemoryUint { _destruct(mem_, sum_, _StackType._EXT_UINT); } + function modadd( + SharedMemory memory mem_, + uint256 a_, + uint256 b_, + uint256 m_, + Destructor d_ + ) internal view returns (uint256 r_) { + r_ = modadd(mem_, a_, b_, m_); + + if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { + _destruct(mem_, a_, _StackType._UINT); + } + + if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { + _destruct(mem_, b_, _StackType._UINT); + } + } + function modsub( SharedMemory memory mem_, uint256 a_, @@ -129,7 +153,7 @@ library MemoryUint { ) internal view returns (uint256 r_) { _checkMemory(mem_, 64); - int cmp_ = _cmp(mem_, a_, b_); + int cmp_ = _cmp(a_, b_); uint256 diff_ = cmp_ >= 0 ? _sub(mem_, a_, b_) : _sub(mem_, b_, a_); uint256 modDiff_ = _mod(mem_, diff_, m_); @@ -145,6 +169,24 @@ library MemoryUint { _destruct(mem_, modDiff_, _StackType._UINT); } + function modsub( + SharedMemory memory mem_, + uint256 a_, + uint256 b_, + uint256 m_, + Destructor d_ + ) internal view returns (uint256 r_) { + r_ = modsub(mem_, a_, b_, m_); + + if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { + _destruct(mem_, a_, _StackType._UINT); + } + + if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { + _destruct(mem_, b_, _StackType._UINT); + } + } + function modmul( SharedMemory memory mem_, uint256 a_, @@ -160,6 +202,24 @@ library MemoryUint { _destruct(mem_, rExt_, _StackType._EXT_UINT); } + function modmul( + SharedMemory memory mem_, + uint256 a_, + uint256 b_, + uint256 m_, + Destructor d_ + ) internal view returns (uint256 r_) { + r_ = modmul(mem_, a_, b_, m_); + + if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { + _destruct(mem_, a_, _StackType._UINT); + } + + if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { + _destruct(mem_, b_, _StackType._UINT); + } + } + function modexp( SharedMemory memory mem_, uint256 a_, @@ -171,6 +231,24 @@ library MemoryUint { return _modexp(mem_, a_, e_, m_); } + function modexp( + SharedMemory memory mem_, + uint256 a_, + uint256 e_, + uint256 m_, + Destructor d_ + ) internal view returns (uint256 r_) { + r_ = modexp(mem_, a_, e_, m_); + + if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { + _destruct(mem_, a_, _StackType._UINT); + } + + if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { + _destruct(mem_, e_, _StackType._UINT); + } + } + function modinv( SharedMemory memory mem_, uint256 a_, @@ -198,10 +276,28 @@ library MemoryUint { _destruct(mem_, bInv_, _StackType._UINT); } - function cmp(SharedMemory memory mem_, uint256 a_, uint256 b_) internal view returns (int) { + function moddiv( + SharedMemory memory mem_, + uint256 a_, + uint256 b_, + uint256 m_, + Destructor d_ + ) internal view returns (uint256 r_) { + r_ = moddiv(mem_, a_, b_, m_); + + if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { + _destruct(mem_, a_, _StackType._UINT); + } + + if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { + _destruct(mem_, b_, _StackType._UINT); + } + } + + function cmp(SharedMemory memory mem_, uint256 a_, uint256 b_) internal pure returns (int) { _checkMemory(mem_, 64); - return _cmp(mem_, a_, b_); + return _cmp(a_, b_); } /// @dev a_, b_ and r_ are of the same size @@ -209,7 +305,7 @@ library MemoryUint { SharedMemory memory mem_, uint256 a_, uint256 b_ - ) private view returns (uint256 r_) { + ) private pure returns (uint256 r_) { r_ = _new(mem_, _valueType(mem_, a_)); assembly { @@ -251,7 +347,7 @@ library MemoryUint { SharedMemory memory mem_, uint256 a_, uint256 b_ - ) private view returns (uint256 r_) { + ) private pure returns (uint256 r_) { r_ = _new(mem_, _valueType(mem_, a_)); assembly { @@ -292,57 +388,87 @@ library MemoryUint { SharedMemory memory mem_, uint256 a_, uint256 b_ - ) private view returns (uint256 r_) { - uint256 aExt_ = _extend(mem_, a_); - uint256 bExt_ = _extend(mem_, b_); - - uint256 sumExt_ = _add(mem_, aExt_, bExt_); - - uint256 two_ = _newUint(mem_, 2); - uint256 maxModExt_ = _newMaxUint(mem_); + ) private pure returns (uint256 r_) { + uint256 rBig_ = _new(mem_, _StackType._CALL); + r_ = _new(mem_, _StackType._EXT_UINT); - uint256 sqSumExt_ = _modexp(mem_, sumExt_, two_, maxModExt_); + assembly { + function get_arg(a, i) -> result { + let idx := div(i, 0x20) + let word := mload(add(add(a, 0x20), mul(shr(1, idx), 0x20))) - _destruct(mem_, sumExt_, _StackType._EXT_UINT); + switch and(idx, 1) + case 0 { + result := shr(128, word) + } + case 1 { + result := shr(128, shl(128, word)) + } + } - int256 cmp_ = _cmp(mem_, a_, b_); + function add_res(r, i, val) { + let ptr := add(r, add(i, 0x20)) - uint256 diffExt_ = cmp_ >= 0 ? _sub(mem_, aExt_, bExt_) : _sub(mem_, bExt_, aExt_); + mstore(ptr, add(mload(ptr), val)) + } - uint256 sqDiffExt_ = _modexp(mem_, diffExt_, two_, maxModExt_); + let argSize_ := shl(1, mload(a_)) // 128 + let resSize_ := shl(1, argSize_) // 256 - _destruct(mem_, aExt_, _StackType._EXT_UINT); - _destruct(mem_, bExt_, _StackType._EXT_UINT); - _destruct(mem_, two_, _StackType._UINT); - _destruct(mem_, maxModExt_, _StackType._EXT_UINT); - _destruct(mem_, diffExt_, _StackType._EXT_UINT); + for { + let i := 0 + } lt(i, argSize_) { + i := add(i, 0x20) + } { + for { + let j := 0 + } lt(j, argSize_) { + j := add(j, 0x20) + } { + let a_i_ := get_arg(a_, i) + let b_j_ := get_arg(b_, j) - r_ = _sub(mem_, sqSumExt_, sqDiffExt_); + let val_ := mul(a_i_, b_j_) - _destruct(mem_, sqSumExt_, _StackType._EXT_UINT); - _destruct(mem_, sqDiffExt_, _StackType._EXT_UINT); + add_res(rBig_, add(i, j), val_) + } + } - assembly { - let rSize_ := mload(r_) - let rPtr_ := add(r_, rSize_) + let rBigPtr_ := add(rBig_, sub(resSize_, 0x20)) for { let i := 0x20 - } lt(i, rSize_) { + } lt(i, resSize_) { i := add(i, 0x20) } { - let rPtrNext_ := sub(rPtr_, 0x20) - let rWord_ := mload(rPtr_) - let rWordNext_ := mload(rPtrNext_) + let rBigPtrNext_ := sub(rBigPtr_, 0x20) + + let carry_ := shr(128, mload(rBigPtr_)) + + mstore(rBigPtr_, shr(128, shl(128, mload(rBigPtr_)))) + mstore(rBigPtrNext_, add(mload(rBigPtrNext_), carry_)) + + rBigPtr_ := rBigPtrNext_ + } + + for { + let i := 0x00 + } lt(i, resSize_) { + i := add(i, 0x40) + } { + let rPtr_ := add(add(r_, 0x20), shr(1, i)) - /// @dev (rWord_ >> 2) | (rWordNext_ << 254) - mstore(rPtr_, or(shr(2, rWord_), shl(254, rWordNext_))) + let highBits_ := mload(add(rBig_, i)) + let lowBits_ := mload(add(rBig_, add(i, 0x20))) - rPtr_ := rPtrNext_ + mstore(rPtr_, add(shl(128, highBits_), lowBits_)) } - mstore(rPtr_, shr(2, mload(rPtr_))) + /// FIXME: fix + mstore(r_, argSize_) } + + _destruct(mem_, rBig_, _StackType._CALL); } function _mod( @@ -413,23 +539,18 @@ library MemoryUint { ) private view returns (uint256 r_) { uint256 two_ = _newUint(mem_, 2); - require(_cmp(mem_, m_, two_) >= 0, "MU: invalid modulus"); + require(_cmp(m_, two_) >= 0, "MU: invalid modulus"); uint256 exponent_ = _sub(mem_, m_, two_); - _destruct(mem_, two_, _StackType._UINT); - r_ = _modexp(mem_, a_, exponent_, m_); + _destruct(mem_, two_, _StackType._UINT); _destruct(mem_, exponent_, _StackType._UINT); } /// @dev a_ and b_ are of the same size - function _cmp( - SharedMemory memory mem_, - uint256 a_, - uint256 b_ - ) private view returns (int256 cmp_) { + function _cmp(uint256 a_, uint256 b_) private pure returns (int256 cmp_) { assembly { let aSize_ := mload(a_) let aPtr_ := add(a_, 0x20) @@ -512,30 +633,30 @@ library MemoryUint { _CALL } - function _checkMemory(SharedMemory memory mem_, uint256 bytesCount_) private view { + function _checkMemory(SharedMemory memory mem_, uint256 bytesCount_) private pure { require(mem_.stack.elementSize == bytesCount_, "MU: invalid memory"); } function _new( SharedMemory memory mem_, _StackType stackType_ - ) private view returns (uint256 value_) { + ) private pure returns (uint256 value_) { if (stackType_ == _StackType._UINT) { - return mem_.stack.push0(); + return mem_.stack.push(); } if (stackType_ == _StackType._EXT_UINT) { - return mem_.extStack.push0(); + return mem_.extStack.push(); } - return mem_.callStack.push0(); + return mem_.callStack.push(); } function _destruct( SharedMemory memory mem_, uint256 value_, _StackType stackType_ - ) private view { + ) private pure { if (stackType_ == _StackType._UINT) { mem_.stack.pop(value_); return; @@ -552,7 +673,7 @@ library MemoryUint { function _memSize( SharedMemory memory mem_, _StackType stackType_ - ) private view returns (uint256) { + ) private pure returns (uint256) { if (stackType_ == _StackType._UINT) { return mem_.stack.elementSize; } @@ -567,7 +688,7 @@ library MemoryUint { function _valueType( SharedMemory memory mem_, uint256 value_ - ) private view returns (_StackType) { + ) private pure returns (_StackType) { uint256 length_; assembly { length_ := mload(value_) @@ -584,7 +705,7 @@ library MemoryUint { return _StackType._CALL; } - function _newUint(SharedMemory memory mem_, uint256 value_) private view returns (uint256 r_) { + function _newUint(SharedMemory memory mem_, uint256 value_) private pure returns (uint256 r_) { uint256 memSize_ = _memSize(mem_, _StackType._UINT); r_ = _new(mem_, _StackType._UINT); @@ -595,7 +716,7 @@ library MemoryUint { } } - function _newMaxUint(SharedMemory memory mem_) private view returns (uint256 r_) { + function _newMaxUint(SharedMemory memory mem_) private pure returns (uint256 r_) { uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); r_ = _new(mem_, _StackType._EXT_UINT); From 1e99c6017fb46e4fb35d1326da4aca414878526e Mon Sep 17 00:00:00 2001 From: joYyHack Date: Thu, 17 Oct 2024 18:08:07 +0300 Subject: [PATCH 15/45] Quick adjustment --- .../PECDSASHA1U384Authenticato.sol | 362 ++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 contracts/passport/authenticators/PECDSASHA1U384Authenticato.sol diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticato.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticato.sol new file mode 100644 index 0000000..4304714 --- /dev/null +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticato.sol @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.16; + +import {SHA1} from "../../utils/SHA1.sol"; +import {U384} from "../../utils/U384.sol"; +import "hardhat/console.sol"; + +/** + * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol + */ +contract PECDSASHA1Authenticator { + using SHA1 for bytes; + using U384 for *; + + // brainpool256r1 parameters + uint256 a = 0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9.init(); + uint256 b = 0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6.init(); + uint256 gx = 0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262.init(); + uint256 gy = 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997.init(); + uint256 p = 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377.init(); + uint256 n = 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7.init(); + + uint256 lowSmax = 0x54fdabedd0f754de1f3305484ec1c6b9371dfb11ea9310141009a40e8fb729bb.init(); + + /** + * @notice Checks active authentication of a passport. ECDSA active authentication is an ECDSA signature of + * raw SHA1 hash of challenge bytes. Usually brainpool256r1 elliptic curve is used. + */ + function authenticate( + bytes memory challenge, + uint256 r, + uint256 s, + uint256 x, + uint256 y + ) external view returns (bool) { + /// @dev accept s only from the lower part of the curve + // if (r == 0 || r >= n || s == 0 || s > lowSmax) { + // return false; + // } + + if (!_isOnCurve(x, y)) { + return false; + } + + uint256 message = uint256(uint160(challenge.sha1())).init(); + + uint256 x1; + uint256 x2; + uint256 y1; + uint256 y2; + + (x1, y1) = _multiplyScalar(gx, gy, U384.moddiv(message, s, n)); + (x2, y2) = _multiplyScalar(x, y, U384.moddiv(r, s, n)); + + uint256[3] memory P = _addAndReturnProjectivePoint(x1, y1, x2, y2); + + console.logBytes32(bytes32(P[0])); + console.logBytes32(bytes32(P[1])); + console.logBytes32(bytes32(P[2])); + + // if (P[2] == 0) { + // return false; + // } + + // uint256 Px = _inverseMod(P[2], p); + // Px = U384.modmul(P[0], U384.modmul(Px, Px, p), p); + + // return Px % n == r; + + return true; + } + + /** + * @dev Multiply an elliptic curve point by a scalar. + */ + function _multiplyScalar( + uint256 x0, + uint256 y0, + uint256 scalar + ) internal view returns (uint256 x1, uint256 y1) { + if (scalar == 0) { + return _zeroAffine(); + } else if (scalar == 1) { + return (x0, y0); + } else if (scalar == 2) { + return _twice(x0, y0); + } + + uint256 base2X = x0; + uint256 base2Y = y0; + uint256 base2Z = 1; + uint256 z1 = 1; + x1 = x0; + y1 = y0; + + if (scalar % 2 == 0) { + x1 = y1 = 0; + } + + scalar = scalar >> 1; + + while (scalar > 0) { + (base2X, base2Y, base2Z) = _twiceProj(base2X, base2Y, base2Z); + + if (scalar % 2 == 1) { + (x1, y1, z1) = _addProj(base2X, base2Y, base2Z, x1, y1, z1); + } + + scalar = scalar >> 1; + } + + return _toAffinePoint(x1, y1, z1); + } + + /** + * @dev Double an elliptic curve point in projective coordinates. See + * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates + */ + function _twiceProj( + uint256 x0, + uint256 y0, + uint256 z0 + ) internal view returns (uint256 x1, uint256 y1, uint256 z1) { + uint256 t; + uint256 u; + uint256 v; + uint256 w; + + if (_isZeroCurve(x0, y0)) { + return _zeroProj(); + } + + u = U384.modmul(y0, z0, p); + u = U384.modmul(u, 2, p); + + v = U384.modmul(u, x0, p); + v = U384.modmul(v, y0, p); + v = U384.modmul(v, 2, p); + + x0 = U384.modmul(x0, x0, p); + t = U384.modmul(x0, 3, p); + + z0 = U384.modmul(z0, z0, p); + z0 = U384.modmul(z0, a, p); + t = U384.modadd(t, z0, p); + + w = U384.modmul(t, t, p); + x0 = U384.modmul(2, v, p); + w = U384.modadd(w, p - x0, p); + + x0 = U384.modadd(v, p - w, p); + x0 = U384.modmul(t, x0, p); + y0 = U384.modmul(y0, u, p); + y0 = U384.modmul(y0, y0, p); + y0 = U384.modmul(2, y0, p); + y1 = U384.modadd(x0, p - y0, p); + + x1 = U384.modmul(u, w, p); + + z1 = U384.modmul(u, u, p); + z1 = U384.modmul(z1, u, p); + } + + /** + * @dev Add two elliptic curve points in projective coordinates. See + * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates + */ + function _addProj( + uint256 x0, + uint256 y0, + uint256 z0, + uint256 x1, + uint256 y1, + uint256 z1 + ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { + uint256 t0; + uint256 t1; + uint256 u0; + uint256 u1; + + if (_isZeroCurve(x0, y0)) { + return (x1, y1, z1); + } else if (_isZeroCurve(x1, y1)) { + return (x0, y0, z0); + } + + t0 = U384.modmul(y0, z1, p); + t1 = U384.modmul(y1, z0, p); + + u0 = U384.modmul(x0, z1, p); + u1 = U384.modmul(x1, z0, p); + + if (u0 == u1) { + if (t0 == t1) { + return _twiceProj(x0, y0, z0); + } else { + return _zeroProj(); + } + } + + (x2, y2, z2) = _addProj2(U384.modmul(z0, z1, p), u0, u1, t1, t0); + } + + /** + * @dev Helper function that splits addProj to avoid too many local variables. + */ + function _addProj2( + uint256 v, + uint256 u0, + uint256 u1, + uint256 t1, + uint256 t0 + ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { + uint256 u; + uint256 u2; + uint256 u3; + uint256 w; + uint256 t; + + t = U384.modadd(t0, p - t1, p); + u = U384.modadd(u0, p - u1, p); + + //u2 = U384.modmul(u, u, p); + u2 = U384.modexp(u, 2, p); + + //w = U384.modmul(t, t, p); + w = U384.modexp(t, 2, p); + + w = U384.modmul(w, v, p); + u1 = U384.modadd(u1, u0, p); + u1 = U384.modmul(u1, u2, p); + w = U384.modadd(w, p - u1, p); + + x2 = U384.modmul(u, w, p); + + u3 = U384.modmul(u2, u, p); + u0 = U384.modmul(u0, u2, p); + u0 = U384.modadd(u0, p - w, p); + t = U384.modmul(t, u0, p); + t0 = U384.modmul(t0, u3, p); + + y2 = U384.modadd(t, p - t0, p); + + z2 = U384.modmul(u3, v, p); + } + + /** + * @dev Add two elliptic curve points in affine coordinates. + */ + function _add( + uint256 x0, + uint256 y0, + uint256 x1, + uint256 y1 + ) internal view returns (uint256, uint256) { + uint256 z0; + + (x0, y0, z0) = _addProj(x0, y0, 1, x1, y1, 1); + + return _toAffinePoint(x0, y0, z0); + } + + /** + * @dev Double an elliptic curve point in affine coordinates. + */ + function _twice(uint256 x0, uint256 y0) internal view returns (uint256, uint256) { + uint256 z0; + + (x0, y0, z0) = _twiceProj(x0, y0, 1); + + return _toAffinePoint(x0, y0, z0); + } + + /** + * @dev Add two points in affine coordinates and return projective point. + */ + function _addAndReturnProjectivePoint( + uint256 x1, + uint256 y1, + uint256 x2, + uint256 y2 + ) internal view returns (uint256[3] memory P) { + uint256 x; + uint256 y; + + (x, y) = _add(x1, y1, x2, y2); + P = _toProjectivePoint(x, y); + } + + /** + * @dev Transform from projective to affine coordinates. + */ + function _toAffinePoint( + uint256 x0, + uint256 y0, + uint256 z0 + ) internal view returns (uint256 x1, uint256 y1) { + x1 = U384.moddiv(x0, z0, p); + y1 = U384.moddiv(y0, z0, p); + } + + /** + * @dev Check if a point in affine coordinates is on the curve. + */ + function _isOnCurve(uint256 x, uint256 y) internal view returns (bool) { + // if (0 == x || x == p || 0 == y || y == p) { + // return false; + // } + + //uint256 LHS = U384.modmul(y, y, p); // y^2 --> modexp(y, 2, p) + uint256 LHS = U384.modexp(y, 2, p); + //uint256 RHS = U384.modmul(U384.modmul(x, x, p), x, p); // x^3 --> modexp(x, 3, p) + uint256 RHS = U384.modexp(x, 3, p); + + if (a != 0) { + RHS = U384.modadd(RHS, U384.modmul(x, a, p), p); // x^3 + a*x + } + + if (b != 0) { + RHS = U384.modadd(RHS, b, p); // x^3 + a*x + b + } + + return LHS == RHS; + } + + /** + * @dev Transform affine coordinates into projective coordinates. + */ + function _toProjectivePoint( + uint256 x0, + uint256 y0 + ) internal view returns (uint256[3] memory P) { + P[2] = U384.modadd(0, 1, p); + P[0] = U384.modmul(x0, P[2], p); + P[1] = U384.modmul(y0, P[2], p); + } + + /** + * @dev Return the zero curve in projective coordinates. + */ + function _zeroProj() internal pure returns (uint256 x, uint256 y, uint256 z) { + return (0.init(), 1.init(), 0.init()); + } + + /** + * @dev Return the zero curve in affine coordinates. + */ + function _zeroAffine() internal pure returns (uint256 x, uint256 y) { + return (0.init(), 0.init()); + } + + /** + * @dev Check if the curve is the zero curve. + */ + function _isZeroCurve(uint256 x0, uint256 y0) internal pure returns (bool isZero) { + if (x0 == 0 && y0 == 0) { + return true; + } + + return false; + } +} From 659053318a9289608b1f6bdf80588e5bb179c42e Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Thu, 17 Oct 2024 18:15:52 +0300 Subject: [PATCH 16/45] added u384 --- contracts/utils/U384.sol | 303 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 contracts/utils/U384.sol diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol new file mode 100644 index 0000000..b7f358e --- /dev/null +++ b/contracts/utils/U384.sol @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.16; + +library U384 { + uint256 private constant SHORT_ALLOCATION = 64; + uint256 private constant CALL_ALLOCATION = 288; + + function init(uint256 from_) internal pure returns (uint256 handler_) { + handler_ = _allocate(SHORT_ALLOCATION); + + assembly { + mstore(add(0x20, handler_), from_) + } + + return handler_; + } + + function init(bytes memory from_) internal view returns (uint256 handler_) { + handler_ = _allocate(SHORT_ALLOCATION); + + assembly { + mstore(handler_, mload(add(from_, 0x20))) + mstore(add(handler_, 0x20), mload(add(from_, 0x40))) + } + + return handler_; + } + + function cmp(uint256 a_, uint256 b_) internal pure returns (int256 cmp_) { + assembly { + let aWord_ := mload(a_) + let bWord_ := mload(b_) + + if gt(aWord_, bWord_) { + mstore(0x00, 0x01) + return(0x00, 0x20) + } + + if lt(aWord_, bWord_) { + mstore(0x00, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0x00, 0x20) + } + + aWord_ := mload(add(a_, 0x20)) + bWord_ := mload(add(b_, 0x20)) + + if gt(aWord_, bWord_) { + mstore(0x00, 0x01) + return(0x00, 0x20) + } + + if lt(aWord_, bWord_) { + mstore(0x00, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0x00, 0x20) + } + + mstore(0x00, 0x00) + return(0x00, 0x20) + } + } + + function moddiv(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + } + + function modexp(uint256 b_, uint256 eInteger_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(CALL_ALLOCATION); + + assembly { + mstore(r_, 0x40) + mstore(add(0x20, r_), 0x20) + mstore(add(0x40, r_), 0x40) + mstore(add(0x60, r_), mload(b_)) + mstore(add(0x80, r_), mload(add(b_, 0x20))) + mstore(add(0xA0, r_), eInteger_) + mstore(add(0xC0, r_), mload(m_)) + mstore(add(0xE0, r_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, r_, 0x0100, r_, 0x40)) { + revert(0, 0) + } + } + + return r_; + } + + function modadd(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(CALL_ALLOCATION); + + _add(a_, b_, r_ + 0x60); + + assembly { + mstore(r_, 0x40) + mstore(add(0x20, r_), 0x20) + mstore(add(0x40, r_), 0x40) + mstore(add(0xA0, r_), 0x01) + mstore(add(0xC0, r_), mload(m_)) + mstore(add(0xE0, r_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, r_, 0x0100, r_, 0x40)) { + revert(0, 0) + } + } + + return r_; + } + + function mod(uint256 a_, uint256 m_) internal view returns (uint256 r_) { + r_ = modexp(a_, 1, m_); + + return r_; + } + + function modsub(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(CALL_ALLOCATION); + + _sub(a_, b_, r_ + 0x60); + + assembly { + mstore(r_, 0x40) + mstore(add(0x20, r_), 0x20) + mstore(add(0x40, r_), 0x40) + mstore(add(0xA0, r_), 0x01) + mstore(add(0xC0, r_), mload(m_)) + mstore(add(0xE0, r_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, r_, 0x0100, r_, 0x40)) { + revert(0, 0) + } + } + + return r_; + } + + function modmul(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(CALL_ALLOCATION); + + _mul(a_, b_, r_ + 0x60); + + assembly { + mstore(r_, 0x60) + mstore(add(0x20, r_), 0x20) + mstore(add(0x40, r_), 0x40) + mstore(add(0xC0, r_), 0x01) + mstore(add(0xE0, r_), mload(m_)) + mstore(add(0x0100, r_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, r_, 0x0120, r_, 0x40)) { + revert(0, 0) + } + } + + return r_; + } + + function add(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { + r_ = _allocate(SHORT_ALLOCATION); + + _add(a_, b_, r_); + + return r_; + } + + function sub(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { + r_ = _allocate(SHORT_ALLOCATION); + + _sub(a_, b_, r_); + + return r_; + } + + function toBytes(uint256 handler_) internal pure returns (bytes memory bytes_) { + assembly { + mstore(bytes_, 0x40) + mstore(add(0x20, bytes_), mload(handler_)) + mstore(add(0x40, bytes_), mload(add(handler_, 0x20))) + } + + return bytes_; + } + + function _add(uint256 a_, uint256 b_, uint256 r_) private pure { + assembly { + let aWord_ := mload(add(a_, 0x20)) + let sum_ := add(aWord_, mload(add(b_, 0x20))) + + mstore(add(r_, 0x20), sum_) + + sum_ := gt(aWord_, sum_) + sum_ := add(sum_, add(mload(a_), mload(b_))) + + mstore(r_, sum_) + } + } + + function _sub(uint256 a_, uint256 b_, uint256 r_) private pure { + assembly { + let aWord_ := mload(add(a_, 0x20)) + let diff_ := sub(aWord_, mload(add(b_, 0x20))) + + mstore(add(r_, 0x20), diff_) + + diff_ := gt(diff_, aWord_) + diff_ := sub(sub(mload(a_), mload(b_)), diff_) + + mstore(r_, diff_) + } + } + + function _mul(uint256 a_, uint256 b_, uint256 r_) private view { + assembly { + function high128(x) -> y { + y := shr(128, x) + } + + function low128(x) -> y { + y := and(x, 0xffffffffffffffffffffffffffffffff) + } + + let a0_ := mload(a_) + let a1_ := high128(mload(add(a_, 0x20))) + let a2_ := low128(mload(add(a_, 0x20))) + + let b0_ := mload(b_) + let b1_ := high128(mload(add(b_, 0x20))) + let b2_ := low128(mload(add(b_, 0x20))) + + // r5 + let current_ := mul(a2_, b2_) + let r5_ := low128(current_) + + // r4 + current_ := shr(128, current_) + + let temp_ := mul(a1_, b2_) + current_ := add(current_, temp_) + let curry_ := lt(current_, temp_) + + temp_ := mul(a2_, b1_) + current_ := add(current_, temp_) + curry_ := add(curry_, lt(current_, temp_)) + + let r4_ := low128(current_) + + // r3 + current_ := add(shl(128, curry_), shr(128, current_)) + curry_ := 0 + + temp_ := mul(a0_, b2_) + current_ := add(current_, temp_) + curry_ := lt(current_, temp_) + + temp_ := mul(a1_, b1_) + current_ := add(current_, temp_) + curry_ := add(curry_, lt(current_, temp_)) + + temp_ := mul(a2_, b0_) + current_ := add(current_, temp_) + curry_ := add(curry_, lt(current_, temp_)) + + let r3_ := low128(current_) + + // r2 + current_ := add(shl(128, curry_), shr(128, current_)) + curry_ := 0 + + temp_ := mul(a0_, b1_) + current_ := add(current_, temp_) + curry_ := lt(current_, temp_) + + temp_ := mul(a1_, b0_) + current_ := add(current_, temp_) + curry_ := add(curry_, lt(current_, temp_)) + + let r2_ := low128(current_) + + // r1 + current_ := add(shl(128, curry_), shr(128, current_)) + curry_ := 0 + + temp_ := mul(a0_, b0_) + current_ := add(current_, temp_) + curry_ := lt(current_, temp_) + + let r1_ := low128(current_) + + // r0 + let r0_ := shr(128, current_) + + mstore(r_, add(shl(128, r0_), r1_)) + mstore(add(r_, 0x20), add(shl(128, r2_), r3_)) + mstore(add(r_, 0x40), add(shl(128, r4_), r5_)) + } + } + + function _allocate(uint256 bytes_) private pure returns (uint256 handler_) { + assembly { + handler_ := mload(0x40) + mstore(0x40, add(handler_, bytes_)) + } + + return handler_; + } +} \ No newline at end of file From 10d729e71d834eb531fb95543f92febb6904aa2d Mon Sep 17 00:00:00 2001 From: joYyHack Date: Thu, 17 Oct 2024 18:25:02 +0300 Subject: [PATCH 17/45] Add test --- ...nticato.sol => PECDSASHA1U384Authenticator.sol} | 2 +- .../authenticators/PECDSAAuthenticator.test.ts | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) rename contracts/passport/authenticators/{PECDSASHA1U384Authenticato.sol => PECDSASHA1U384Authenticator.sol} (99%) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticato.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol similarity index 99% rename from contracts/passport/authenticators/PECDSASHA1U384Authenticato.sol rename to contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 4304714..75a2358 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticato.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -8,7 +8,7 @@ import "hardhat/console.sol"; /** * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol */ -contract PECDSASHA1Authenticator { +contract PECDSASHA1U384Authenticator { using SHA1 for bytes; using U384 for *; diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts index f2443af..613ba13 100644 --- a/test/passport/authenticators/PECDSAAuthenticator.test.ts +++ b/test/passport/authenticators/PECDSAAuthenticator.test.ts @@ -4,7 +4,12 @@ import { expect } from "chai"; import { Reverter } from "@/test/helpers/"; import { inverseMod, toAffinePoint, multiplyScalar, addProj, n, p, gx, gy, modmul } from "@/test/helpers/"; -import { PECDSASHA1Authenticator, PECDSASHA2Authenticator, PECDSASHA2NewAuthenticator } from "@ethers-v6"; +import { + PECDSASHA1Authenticator, + PECDSASHA2Authenticator, + PECDSASHA2NewAuthenticator, + PECDSASHA1U384Authenticator, +} from "@ethers-v6"; describe("PECDSAAuthenticator", () => { const reverter = new Reverter(); @@ -12,15 +17,18 @@ describe("PECDSAAuthenticator", () => { let authSha1: PECDSASHA1Authenticator; let authSha2: PECDSASHA2Authenticator; let authSha2New: PECDSASHA2NewAuthenticator; + let authU384: PECDSASHA1U384Authenticator; before("setup", async () => { const PECDSASHA1Authenticator = await ethers.getContractFactory("PECDSASHA1Authenticator"); const PECDSASHA2Authenticator = await ethers.getContractFactory("PECDSASHA2Authenticator"); const PECDSASHA2NewAuthenticator = await ethers.getContractFactory("PECDSASHA2NewAuthenticator"); + const PECDSASHA1U384Authenticator = await ethers.getContractFactory("PECDSASHA1U384Authenticator"); authSha1 = await PECDSASHA1Authenticator.deploy(); authSha2 = await PECDSASHA2Authenticator.deploy(); authSha2New = await PECDSASHA2NewAuthenticator.deploy(); + authU384 = await PECDSASHA1U384Authenticator.deploy(); await reverter.snapshot(); }); @@ -28,7 +36,7 @@ describe("PECDSAAuthenticator", () => { afterEach(reverter.revert); describe("#authenticate", () => { - it.only("should authenticate passport - brainpool256r1 & sha1", async () => { + it("should authenticate passport - brainpool256r1 & sha1", async () => { const challenge = "0xe7938ea62eb1980a"; const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; @@ -67,7 +75,7 @@ describe("PECDSAAuthenticator", () => { const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; //await authSha2New.forTest(y); - expect(await authSha2New.authenticate(challenge, r, s, x, y)).to.be.false; + expect(await authU384.authenticate(challenge, r, s, x, y)).to.be.false; // console.log(gx, gy, modmul(BigInt(ethers.sha256(challenge)), sInv, n)); From ed82a5621aae2e7a0d0e3c204ec0cea9885dcde0 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Thu, 17 Oct 2024 21:53:04 +0300 Subject: [PATCH 18/45] all its --- .../PECDSASHA1U384Authenticator.sol | 336 +++++++++++------- contracts/utils/U384.sol | 113 ++++-- .../PECDSAAuthenticator.test.ts | 28 +- 3 files changed, 312 insertions(+), 165 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 75a2358..5b15941 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -12,51 +12,96 @@ contract PECDSASHA1U384Authenticator { using SHA1 for bytes; using U384 for *; - // brainpool256r1 parameters - uint256 a = 0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9.init(); - uint256 b = 0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6.init(); - uint256 gx = 0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262.init(); - uint256 gy = 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997.init(); - uint256 p = 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377.init(); - uint256 n = 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7.init(); + struct Parameters { + uint256 a; + uint256 b; + uint256 gx; + uint256 gy; + uint256 p; + uint256 n; + uint256 lowSmax; + } - uint256 lowSmax = 0x54fdabedd0f754de1f3305484ec1c6b9371dfb11ea9310141009a40e8fb729bb.init(); + struct Inputs { + bytes challenge; + bytes r; + bytes s; + bytes x; + bytes y; + } + + function authenticate( + bytes memory challenge, + bytes memory r, + bytes memory s, + bytes memory x, + bytes memory y + ) external view returns (bool) { + return _authenticate(challenge, U384.init(r), U384.init(s), U384.init(x), U384.init(y)); + } /** * @notice Checks active authentication of a passport. ECDSA active authentication is an ECDSA signature of * raw SHA1 hash of challenge bytes. Usually brainpool256r1 elliptic curve is used. */ - function authenticate( + function _authenticate( bytes memory challenge, uint256 r, uint256 s, uint256 x, uint256 y - ) external view returns (bool) { + ) internal view returns (bool) { /// @dev accept s only from the lower part of the curve // if (r == 0 || r >= n || s == 0 || s > lowSmax) { // return false; // } - - if (!_isOnCurve(x, y)) { - return false; +// BigIntOpt aOpt = +// hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" +// .initOpt(false); +// BigIntOpt bOpt = +// hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF" +// .initOpt(false); +// BigIntOpt gxOpt = +// hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" +// .initOpt(false); +// BigIntOpt gyOpt = +// hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" +// .initOpt(false); +// BigIntOpt pOpt = +// hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" +// .initOpt(false); +// BigIntOpt nOpt = +// hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" +// .initOpt(false); +// +// BigIntOpt lowSmaxOpt = +// hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" +// .initOpt(false); + // brainpool256r1 parameters + Parameters memory params = Parameters({ + a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC".init(), + b: hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF".init(), + gx: hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7".init(), + gy: hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f".init(), + p: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF".init(), + n: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973".init(), + lowSmax: hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b".init() + }); + + if (!_isOnCurve(params, x, y)) { + //return false; } - uint256 message = uint256(uint160(challenge.sha1())).init(); - - uint256 x1; - uint256 x2; - uint256 y1; - uint256 y2; + uint256 message = uint256(sha256(challenge)).init(); - (x1, y1) = _multiplyScalar(gx, gy, U384.moddiv(message, s, n)); - (x2, y2) = _multiplyScalar(x, y, U384.moddiv(r, s, n)); + (uint256 x1, uint256 y1) = _multiplyScalar(params, params.gx, params.gy, U384.moddiv(message, s, params.n)); + (uint256 x2, uint256 y2) = _multiplyScalar(params, x, y, U384.moddiv(r, s, params.n)); - uint256[3] memory P = _addAndReturnProjectivePoint(x1, y1, x2, y2); + uint256[3] memory P = _addAndReturnProjectivePoint(params, x1, y1, x2, y2); - console.logBytes32(bytes32(P[0])); - console.logBytes32(bytes32(P[1])); - console.logBytes32(bytes32(P[2])); + console.logBytes(P[0].toBytes()); + console.logBytes(P[1].toBytes()); + console.logBytes(P[2].toBytes()); // if (P[2] == 0) { // return false; @@ -74,42 +119,59 @@ contract PECDSASHA1U384Authenticator { * @dev Multiply an elliptic curve point by a scalar. */ function _multiplyScalar( + Parameters memory params, uint256 x0, uint256 y0, uint256 scalar ) internal view returns (uint256 x1, uint256 y1) { - if (scalar == 0) { + if (U384.cmpInteger(scalar, 0) == 0) { return _zeroAffine(); - } else if (scalar == 1) { + } else if (U384.cmpInteger(scalar, 1) == 0) { return (x0, y0); - } else if (scalar == 2) { - return _twice(x0, y0); + } else if (U384.cmpInteger(scalar, 2) == 0) { + return _twice(params, x0, y0); } uint256 base2X = x0; uint256 base2Y = y0; - uint256 base2Z = 1; - uint256 z1 = 1; - x1 = x0; - y1 = y0; + uint256 base2Z = U384.init(1); + uint256 z1 = U384.init(1); - if (scalar % 2 == 0) { - x1 = y1 = 0; + uint256 highBits_; + uint256 lowBits_; + + assembly { + highBits_ := mload(scalar) + lowBits_ := mload(add(scalar, 0x20)) + } + + if (lowBits_ % 2 == 1) { + x1 = U384.init(0); + y1 = U384.init(0); + } else { + x1 = U384.copy(x0); + y1 = U384.copy(y0); } - scalar = scalar >> 1; + lowBits_ >>= 1; + lowBits_ |= highBits_ << 255; + highBits_ >>= 1; - while (scalar > 0) { - (base2X, base2Y, base2Z) = _twiceProj(base2X, base2Y, base2Z); + for (uint256 i = 0; i < 128; ++i) { + (base2X, base2Y, base2Z) = _twiceProj(params, base2X, base2Y, base2Z); - if (scalar % 2 == 1) { - (x1, y1, z1) = _addProj(base2X, base2Y, base2Z, x1, y1, z1); + if (lowBits_ % 2 == 1) { + (x1, y1, z1) = _addProj(params, base2X, base2Y, base2Z, x1, y1, z1); } - scalar = scalar >> 1; + lowBits_ >>= 1; + lowBits_ |= highBits_ << 255; + highBits_ >>= 1; + + console.log("gas", 300_000_000 - gasleft()); } - return _toAffinePoint(x1, y1, z1); + return _toAffinePoint(params, x1, y1, z1); } /** @@ -117,6 +179,7 @@ contract PECDSASHA1U384Authenticator { * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates */ function _twiceProj( + Parameters memory params, uint256 x0, uint256 y0, uint256 z0 @@ -130,35 +193,45 @@ contract PECDSASHA1U384Authenticator { return _zeroProj(); } - u = U384.modmul(y0, z0, p); - u = U384.modmul(u, 2, p); + uint256 two = U384.init(2); + uint256 three = U384.init(3); + + u = U384.modmul(y0, z0, params.p); + u = U384.modmul(u, two, params.p); - v = U384.modmul(u, x0, p); - v = U384.modmul(v, y0, p); - v = U384.modmul(v, 2, p); + v = U384.modmul(u, x0, params.p); + v = U384.modmul(v, y0, params.p); + v = U384.modmul(v, two, params.p); - x0 = U384.modmul(x0, x0, p); - t = U384.modmul(x0, 3, p); + x0 = U384.modmul(x0, x0, params.p); + t = U384.modmul(x0, three, params.p); - z0 = U384.modmul(z0, z0, p); - z0 = U384.modmul(z0, a, p); - t = U384.modadd(t, z0, p); + z0 = U384.modmul(z0, z0, params.p); + z0 = U384.modmul(z0, params.a, params.p); + t = U384.modadd(t, z0, params.p); - w = U384.modmul(t, t, p); - x0 = U384.modmul(2, v, p); - w = U384.modadd(w, p - x0, p); + w = U384.modmul(t, t, params.p); + x0 = U384.modmul(two, v, params.p); + w = U384.modadd(w, U384.sub(params.p, x0), params.p); - x0 = U384.modadd(v, p - w, p); - x0 = U384.modmul(t, x0, p); - y0 = U384.modmul(y0, u, p); - y0 = U384.modmul(y0, y0, p); - y0 = U384.modmul(2, y0, p); - y1 = U384.modadd(x0, p - y0, p); + x0 = U384.modadd(v, U384.sub(params.p, w), params.p); + x0 = U384.modmul(t, x0, params.p); + y0 = U384.modmul(y0, u, params.p); + y0 = U384.modmul(y0, y0, params.p); + y0 = U384.modmul(two, y0, params.p); + y1 = U384.modadd(x0, U384.sub(params.p, y0), params.p); - x1 = U384.modmul(u, w, p); + x1 = U384.modmul(u, w, params.p); - z1 = U384.modmul(u, u, p); - z1 = U384.modmul(z1, u, p); + z1 = U384.modmul(u, u, params.p); + z1 = U384.modmul(z1, u, params.p); + } + + struct UT { + uint256 u0; + uint256 u1; + uint256 t0; + uint256 t1; } /** @@ -166,6 +239,7 @@ contract PECDSASHA1U384Authenticator { * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates */ function _addProj( + Parameters memory params, uint256 x0, uint256 y0, uint256 z0, @@ -173,81 +247,83 @@ contract PECDSASHA1U384Authenticator { uint256 y1, uint256 z1 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { - uint256 t0; - uint256 t1; - uint256 u0; - uint256 u1; - if (_isZeroCurve(x0, y0)) { return (x1, y1, z1); } else if (_isZeroCurve(x1, y1)) { return (x0, y0, z0); } - t0 = U384.modmul(y0, z1, p); - t1 = U384.modmul(y1, z0, p); + UT memory ut; - u0 = U384.modmul(x0, z1, p); - u1 = U384.modmul(x1, z0, p); + ut.t0 = U384.modmul(y0, z1, params.p); + ut.t1 = U384.modmul(y1, z0, params.p); + ut.u0 = U384.modmul(x0, z1, params.p); + ut.u1 = U384.modmul(x1, z0, params.p); - if (u0 == u1) { - if (t0 == t1) { - return _twiceProj(x0, y0, z0); + if (U384.cmp(ut.u0, ut.u1) == 0) { + if (U384.cmp(ut.t0, ut.t1) == 0) { + return _twiceProj(params, x0, y0, z0); } else { return _zeroProj(); } } - (x2, y2, z2) = _addProj2(U384.modmul(z0, z1, p), u0, u1, t1, t0); + (x2, y2, z2) = _addProj2(params, U384.modmul(z0, z1, params.p), ut.u0, ut.u1, ut.t1, ut.t0); + } + + struct UTW { + uint256 u; + uint256 u2; + uint256 u3; + uint256 w; + uint256 t; } /** * @dev Helper function that splits addProj to avoid too many local variables. */ function _addProj2( + Parameters memory params, uint256 v, uint256 u0, uint256 u1, uint256 t1, uint256 t0 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { - uint256 u; - uint256 u2; - uint256 u3; - uint256 w; - uint256 t; + UTW memory utw; - t = U384.modadd(t0, p - t1, p); - u = U384.modadd(u0, p - u1, p); + utw.t = U384.modadd(t0, U384.sub(params.p, t1), params.p); + utw.u = U384.modadd(u0, U384.sub(params.p, u1), params.p); //u2 = U384.modmul(u, u, p); - u2 = U384.modexp(u, 2, p); + utw.u2 = U384.modexp(utw.u, 2, params.p); //w = U384.modmul(t, t, p); - w = U384.modexp(t, 2, p); + utw.w = U384.modexp(utw.t, 2, params.p); - w = U384.modmul(w, v, p); - u1 = U384.modadd(u1, u0, p); - u1 = U384.modmul(u1, u2, p); - w = U384.modadd(w, p - u1, p); + utw.w = U384.modmul(utw.w, v, params.p); + u1 = U384.modadd(u1, u0, params.p); + u1 = U384.modmul(u1, utw.u2, params.p); + utw.w = U384.modadd(utw.w, U384.sub(params.p, u1), params.p); - x2 = U384.modmul(u, w, p); + x2 = U384.modmul(utw.u, utw.w, params.p); - u3 = U384.modmul(u2, u, p); - u0 = U384.modmul(u0, u2, p); - u0 = U384.modadd(u0, p - w, p); - t = U384.modmul(t, u0, p); - t0 = U384.modmul(t0, u3, p); + utw.u3 = U384.modmul(utw.u2, utw.u, params.p); + u0 = U384.modmul(u0, utw.u2, params.p); + u0 = U384.modadd(u0, U384.sub(params.p, utw.w), params.p); + utw.t = U384.modmul(utw.t, u0, params.p); + t0 = U384.modmul(t0, utw.u3, params.p); - y2 = U384.modadd(t, p - t0, p); + y2 = U384.modadd(utw.t, U384.sub(params.p, t0), params.p); - z2 = U384.modmul(u3, v, p); + z2 = U384.modmul(utw.u3, v, params.p); } /** * @dev Add two elliptic curve points in affine coordinates. */ function _add( + Parameters memory params, uint256 x0, uint256 y0, uint256 x1, @@ -255,26 +331,27 @@ contract PECDSASHA1U384Authenticator { ) internal view returns (uint256, uint256) { uint256 z0; - (x0, y0, z0) = _addProj(x0, y0, 1, x1, y1, 1); + (x0, y0, z0) = _addProj(params, x0, y0, 1, x1, y1, 1); - return _toAffinePoint(x0, y0, z0); + return _toAffinePoint(params,x0, y0, z0); } /** * @dev Double an elliptic curve point in affine coordinates. */ - function _twice(uint256 x0, uint256 y0) internal view returns (uint256, uint256) { + function _twice(Parameters memory params, uint256 x0, uint256 y0) internal view returns (uint256, uint256) { uint256 z0; - (x0, y0, z0) = _twiceProj(x0, y0, 1); + (x0, y0, z0) = _twiceProj(params, x0, y0, U384.init(1)); - return _toAffinePoint(x0, y0, z0); + return _toAffinePoint(params,x0, y0, z0); } /** * @dev Add two points in affine coordinates and return projective point. */ function _addAndReturnProjectivePoint( + Parameters memory params, uint256 x1, uint256 y1, uint256 x2, @@ -283,80 +360,83 @@ contract PECDSASHA1U384Authenticator { uint256 x; uint256 y; - (x, y) = _add(x1, y1, x2, y2); - P = _toProjectivePoint(x, y); + (x, y) = _add(params, x1, y1, x2, y2); + P = _toProjectivePoint(params,x, y); } /** * @dev Transform from projective to affine coordinates. */ function _toAffinePoint( + Parameters memory params, uint256 x0, uint256 y0, uint256 z0 ) internal view returns (uint256 x1, uint256 y1) { - x1 = U384.moddiv(x0, z0, p); - y1 = U384.moddiv(y0, z0, p); + x1 = U384.moddiv(x0, z0, params.p); + y1 = U384.moddiv(y0, z0, params.p); } /** * @dev Check if a point in affine coordinates is on the curve. */ - function _isOnCurve(uint256 x, uint256 y) internal view returns (bool) { - // if (0 == x || x == p || 0 == y || y == p) { - // return false; - // } + function _isOnCurve(Parameters memory params, uint256 x, uint256 y) internal view returns (bool) { + if ( + U384.cmpInteger(x, 0) == 0 || + U384.cmp(x, params.p) == 0 || + U384.cmpInteger(y, 0) == 0 || + U384.cmp(y, params.p) == 0 + ) { + return false; + } //uint256 LHS = U384.modmul(y, y, p); // y^2 --> modexp(y, 2, p) - uint256 LHS = U384.modexp(y, 2, p); + uint256 LHS = U384.modexp(y, 2, params.p); //uint256 RHS = U384.modmul(U384.modmul(x, x, p), x, p); // x^3 --> modexp(x, 3, p) - uint256 RHS = U384.modexp(x, 3, p); + uint256 RHS = U384.modexp(x, 3, params.p); - if (a != 0) { - RHS = U384.modadd(RHS, U384.modmul(x, a, p), p); // x^3 + a*x + if (U384.cmpInteger(params.a, 0) != 0) { + RHS = U384.modadd(RHS, U384.modmul(x, params.a, params.p), params.p); // x^3 + a*x } - if (b != 0) { - RHS = U384.modadd(RHS, b, p); // x^3 + a*x + b + if (U384.cmpInteger(params.b, 0) != 0) { + RHS = U384.modadd(RHS, params.b, params.p); // x^3 + a*x + b } - return LHS == RHS; + return U384.cmp(LHS, RHS) == 0; } /** * @dev Transform affine coordinates into projective coordinates. */ function _toProjectivePoint( + Parameters memory params, uint256 x0, uint256 y0 ) internal view returns (uint256[3] memory P) { - P[2] = U384.modadd(0, 1, p); - P[0] = U384.modmul(x0, P[2], p); - P[1] = U384.modmul(y0, P[2], p); + P[2] = U384.modadd(U384.init(0), U384.init(1), params.p); + P[0] = U384.modmul(x0, P[2], params.p); + P[1] = U384.modmul(y0, P[2], params.p); } /** * @dev Return the zero curve in projective coordinates. */ function _zeroProj() internal pure returns (uint256 x, uint256 y, uint256 z) { - return (0.init(), 1.init(), 0.init()); + return (U384.init(0), U384.init(1), U384.init(0)); } /** * @dev Return the zero curve in affine coordinates. */ function _zeroAffine() internal pure returns (uint256 x, uint256 y) { - return (0.init(), 0.init()); + return (U384.init(0), U384.init(0)); } /** * @dev Check if the curve is the zero curve. */ function _isZeroCurve(uint256 x0, uint256 y0) internal pure returns (bool isZero) { - if (x0 == 0 && y0 == 0) { - return true; - } - - return false; + return U384.cmpInteger(x0, 0) == 0 && U384.cmpInteger(y0, 0) == 0; } } diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index b7f358e..628665e 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -26,40 +26,74 @@ library U384 { return handler_; } + function copy(uint256 handler_) internal view returns (uint256 handlerCopy_) { + handlerCopy_ = _allocate(SHORT_ALLOCATION); + + assembly { + mstore(handlerCopy_, mload(handler_)) + mstore(add(handlerCopy_, 0x20), mload(add(handler_, 0x20))) + } + + return handlerCopy_; + } + function cmp(uint256 a_, uint256 b_) internal pure returns (int256 cmp_) { + uint256 aWord_; + uint256 bWord_; + assembly { - let aWord_ := mload(a_) - let bWord_ := mload(b_) + aWord_ := mload(a_) + bWord_ := mload(b_) + } - if gt(aWord_, bWord_) { - mstore(0x00, 0x01) - return(0x00, 0x20) - } + if (aWord_ > bWord_) { + return 1; + } - if lt(aWord_, bWord_) { - mstore(0x00, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) - return(0x00, 0x20) - } + if (aWord_ < bWord_) { + return -1; + } + assembly { aWord_ := mload(add(a_, 0x20)) bWord_ := mload(add(b_, 0x20)) + } - if gt(aWord_, bWord_) { - mstore(0x00, 0x01) - return(0x00, 0x20) - } - - if lt(aWord_, bWord_) { - mstore(0x00, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) - return(0x00, 0x20) - } + if (aWord_ > bWord_) { + return 1; + } - mstore(0x00, 0x00) - return(0x00, 0x20) + if (aWord_ < bWord_) { + return -1; } + + return 0; } - function moddiv(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + function cmpInteger(uint256 a_, uint256 bInteger_) internal pure returns (int256 cmp_) { + uint256 aWord_; + + assembly { + aWord_ := mload(a_) + } + + if (aWord_ > 0) { + return 1; + } + + assembly { + aWord_ := mload(add(a_, 0x20)) + } + + if (aWord_ > bInteger_) { + return 1; + } + + if (aWord_ < bInteger_) { + return -1; + } + + return 0; } function modexp(uint256 b_, uint256 eInteger_, uint256 m_) internal view returns (uint256 r_) { @@ -152,6 +186,35 @@ library U384 { return r_; } + /* + mes 779149564533142355434093157610126726613246737199 + s 29118654464229156312755475164902924590603964377702716942232927993582928167089 + sInv 23250782235154357312578844266810365056083274447761806887500655809183072055193 + n 76884956397045344220809746629001649092737531784414529538755519063063536359079 + -> 30823410400962253491978005949535646087432096635784775122170630924100507445065 + */ + function moddiv(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(CALL_ALLOCATION); + + uint256 two_ = init(2); + + _sub(m_, two_, r_ + 0xA0); + + assembly { + mstore(r_, 0x40) + mstore(add(0x20, r_), 0x40) + mstore(add(0x40, r_), 0x40) + mstore(add(0x60, r_), mload(b_)) + mstore(add(0x80, r_), mload(add(b_, 0x20))) + mstore(add(0xE0, r_), mload(m_)) + mstore(add(0x0100, r_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, r_, 0x0120, r_, 0x40)) { + revert(0, 0) + } + } + } + function add(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { r_ = _allocate(SHORT_ALLOCATION); @@ -169,7 +232,11 @@ library U384 { } function toBytes(uint256 handler_) internal pure returns (bytes memory bytes_) { + uint256 bytesHandler_ = _allocate(96); + assembly { + bytes_ := bytesHandler_ + mstore(bytes_, 0x40) mstore(add(0x20, bytes_), mload(handler_)) mstore(add(0x40, bytes_), mload(add(handler_, 0x20))) @@ -300,4 +367,4 @@ library U384 { return handler_; } -} \ No newline at end of file +} diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts index 613ba13..6f9b9ce 100644 --- a/test/passport/authenticators/PECDSAAuthenticator.test.ts +++ b/test/passport/authenticators/PECDSAAuthenticator.test.ts @@ -59,20 +59,20 @@ describe("PECDSAAuthenticator", () => { }); it.only("should authenticate passport - secp384r1 & sha2 new", async () => { - // const challenge = - // "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; - - // const r = "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63"; - // const s = "0xf1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd"; - // const x = "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6"; - // const y = "0x1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; - - const challenge = "0xe7938ea62eb1980a"; - - const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; - const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; - const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; - const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; + const challenge = + "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; + + const r = "0x" + "3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63".padStart(128, "0"); + const s = "0x" + "f1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd".padStart(128, "0"); + const x = "0x" + "56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6".padStart(128, "0"); + const y = "0x" + "1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a".padStart(128, "0"); + + // const challenge = "0xe7938ea62eb1980a"; + // + // const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; + // const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; + // const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; + // const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; //await authSha2New.forTest(y); expect(await authU384.authenticate(challenge, r, s, x, y)).to.be.false; From 6e6953040e1aa92a86b4000b5418f1dd9fceb47f Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 18 Oct 2024 17:03:08 +0300 Subject: [PATCH 19/45] 512 its 70kk right answers!!! --- .../PECDSASHA1Authenticator.sol | 7 ++ .../PECDSASHA1U384Authenticator.sol | 75 +++++++------------ contracts/utils/U384.sol | 13 ++-- .../PECDSAAuthenticator.test.ts | 26 +++---- 4 files changed, 53 insertions(+), 68 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol index 221d258..9e29380 100644 --- a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol @@ -50,7 +50,14 @@ contract PECDSASHA1Authenticator { uint256 sInv = _inverseMod(s, n); (x1, y1) = _multiplyScalar(gx, gy, mulmod(message, sInv, n)); + console.log("x1y1"); + console.logBytes32(bytes32(x1)); + console.logBytes32(bytes32(y1)); + (x2, y2) = _multiplyScalar(x, y, mulmod(r, sInv, n)); + console.log("x2y2"); + console.logBytes32(bytes32(x2)); + console.logBytes32(bytes32(y2)); uint256[3] memory P = _addAndReturnProjectivePoint(x1, y1, x2, y2); diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 5b15941..03f700d 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -30,72 +30,53 @@ contract PECDSASHA1U384Authenticator { bytes y; } - function authenticate( - bytes memory challenge, - bytes memory r, - bytes memory s, - bytes memory x, - bytes memory y - ) external view returns (bool) { - return _authenticate(challenge, U384.init(r), U384.init(s), U384.init(x), U384.init(y)); - } - /** * @notice Checks active authentication of a passport. ECDSA active authentication is an ECDSA signature of * raw SHA1 hash of challenge bytes. Usually brainpool256r1 elliptic curve is used. */ - function _authenticate( + function authenticate( bytes memory challenge, uint256 r, uint256 s, uint256 x, uint256 y - ) internal view returns (bool) { + ) external view returns (bool) { /// @dev accept s only from the lower part of the curve // if (r == 0 || r >= n || s == 0 || s > lowSmax) { // return false; // } -// BigIntOpt aOpt = -// hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" -// .initOpt(false); -// BigIntOpt bOpt = -// hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF" -// .initOpt(false); -// BigIntOpt gxOpt = -// hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" -// .initOpt(false); -// BigIntOpt gyOpt = -// hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" -// .initOpt(false); -// BigIntOpt pOpt = -// hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" -// .initOpt(false); -// BigIntOpt nOpt = -// hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" -// .initOpt(false); -// -// BigIntOpt lowSmaxOpt = -// hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" -// .initOpt(false); + + r = U384.init(r); + s = U384.init(s); + x = U384.init(x); + y = U384.init(y); + // brainpool256r1 parameters Parameters memory params = Parameters({ - a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC".init(), - b: hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF".init(), - gx: hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7".init(), - gy: hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f".init(), - p: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF".init(), - n: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973".init(), - lowSmax: hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b".init() + a: 0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9.init(), + b: 0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6.init(), + gx: 0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262.init(), + gy: 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997.init(), + p: 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377.init(), + n: 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7.init(), + lowSmax: 0x54fdabedd0f754de1f3305484ec1c6b9371dfb11ea9310141009a40e8fb729bb.init() }); if (!_isOnCurve(params, x, y)) { - //return false; + return false; } - uint256 message = uint256(sha256(challenge)).init(); + uint256 message = uint256(uint160(challenge.sha1())).init(); (uint256 x1, uint256 y1) = _multiplyScalar(params, params.gx, params.gy, U384.moddiv(message, s, params.n)); + console.log("x1y1"); + console.logBytes(U384.toBytes(x1)); + console.logBytes(U384.toBytes(y1)); + (uint256 x2, uint256 y2) = _multiplyScalar(params, x, y, U384.moddiv(r, s, params.n)); + console.log("x2y2"); + console.logBytes(U384.toBytes(x2)); + console.logBytes(U384.toBytes(y2)); uint256[3] memory P = _addAndReturnProjectivePoint(params, x1, y1, x2, y2); @@ -145,7 +126,7 @@ contract PECDSASHA1U384Authenticator { lowBits_ := mload(add(scalar, 0x20)) } - if (lowBits_ % 2 == 1) { + if (lowBits_ % 2 == 0) { x1 = U384.init(0); y1 = U384.init(0); } else { @@ -157,7 +138,7 @@ contract PECDSASHA1U384Authenticator { lowBits_ |= highBits_ << 255; highBits_ >>= 1; - for (uint256 i = 0; i < 128; ++i) { + while (lowBits_ > 0 || highBits_ > 0) { (base2X, base2Y, base2Z) = _twiceProj(params, base2X, base2Y, base2Z); if (lowBits_ % 2 == 1) { @@ -168,7 +149,7 @@ contract PECDSASHA1U384Authenticator { lowBits_ |= highBits_ << 255; highBits_ >>= 1; - console.log("gas", 300_000_000 - gasleft()); + //console.log("gas", 300_000_000 - gasleft()); } return _toAffinePoint(params, x1, y1, z1); @@ -331,7 +312,7 @@ contract PECDSASHA1U384Authenticator { ) internal view returns (uint256, uint256) { uint256 z0; - (x0, y0, z0) = _addProj(params, x0, y0, 1, x1, y1, 1); + (x0, y0, z0) = _addProj(params, x0, y0, U384.init(1), x1, y1, U384.init(1)); return _toAffinePoint(params,x0, y0, z0); } diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 628665e..08e42f8 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -3,12 +3,14 @@ pragma solidity 0.8.16; library U384 { uint256 private constant SHORT_ALLOCATION = 64; + uint256 private constant LONG_ALLOCATION = 96; uint256 private constant CALL_ALLOCATION = 288; function init(uint256 from_) internal pure returns (uint256 handler_) { handler_ = _allocate(SHORT_ALLOCATION); assembly { + mstore(handler_, 0x00) mstore(add(0x20, handler_), from_) } @@ -186,13 +188,6 @@ library U384 { return r_; } - /* - mes 779149564533142355434093157610126726613246737199 - s 29118654464229156312755475164902924590603964377702716942232927993582928167089 - sInv 23250782235154357312578844266810365056083274447761806887500655809183072055193 - n 76884956397045344220809746629001649092737531784414529538755519063063536359079 - -> 30823410400962253491978005949535646087432096635784775122170630924100507445065 - */ function moddiv(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { r_ = _allocate(CALL_ALLOCATION); @@ -213,6 +208,8 @@ library U384 { revert(0, 0) } } + + return modmul(a_, r_, m_); } function add(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { @@ -232,7 +229,7 @@ library U384 { } function toBytes(uint256 handler_) internal pure returns (bytes memory bytes_) { - uint256 bytesHandler_ = _allocate(96); + uint256 bytesHandler_ = _allocate(LONG_ALLOCATION); assembly { bytes_ := bytesHandler_ diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts index 6f9b9ce..54144be 100644 --- a/test/passport/authenticators/PECDSAAuthenticator.test.ts +++ b/test/passport/authenticators/PECDSAAuthenticator.test.ts @@ -36,7 +36,7 @@ describe("PECDSAAuthenticator", () => { afterEach(reverter.revert); describe("#authenticate", () => { - it("should authenticate passport - brainpool256r1 & sha1", async () => { + it.only("should authenticate passport - brainpool256r1 & sha1", async () => { const challenge = "0xe7938ea62eb1980a"; const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; @@ -59,20 +59,20 @@ describe("PECDSAAuthenticator", () => { }); it.only("should authenticate passport - secp384r1 & sha2 new", async () => { - const challenge = - "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; + // const challenge = + // "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; + // + // const r = "0x" + "3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63".padStart(128, "0"); + // const s = "0x" + "f1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd".padStart(128, "0"); + // const x = "0x" + "56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6".padStart(128, "0"); + // const y = "0x" + "1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a".padStart(128, "0"); - const r = "0x" + "3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63".padStart(128, "0"); - const s = "0x" + "f1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd".padStart(128, "0"); - const x = "0x" + "56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6".padStart(128, "0"); - const y = "0x" + "1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a".padStart(128, "0"); + const challenge = "0xe7938ea62eb1980a"; - // const challenge = "0xe7938ea62eb1980a"; - // - // const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; - // const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; - // const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; - // const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; + const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; + const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; + const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; + const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; //await authSha2New.forTest(y); expect(await authU384.authenticate(challenge, r, s, x, y)).to.be.false; From 0fd14e5aacaf01e5c56b061de76387093266ff18 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 18 Oct 2024 14:16:58 +0300 Subject: [PATCH 20/45] added eq fns --- .../PECDSASHA1U384Authenticator.sol | 26 +++++++++---------- contracts/utils/U384.sol | 12 +++++++++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 03f700d..46abeef 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -105,11 +105,11 @@ contract PECDSASHA1U384Authenticator { uint256 y0, uint256 scalar ) internal view returns (uint256 x1, uint256 y1) { - if (U384.cmpInteger(scalar, 0) == 0) { + if (U384.eqInteger(scalar, 0)) { return _zeroAffine(); - } else if (U384.cmpInteger(scalar, 1) == 0) { + } else if (U384.eqInteger(scalar, 1)) { return (x0, y0); - } else if (U384.cmpInteger(scalar, 2) == 0) { + } else if (U384.eqInteger(scalar, 2)) { return _twice(params, x0, y0); } @@ -241,8 +241,8 @@ contract PECDSASHA1U384Authenticator { ut.u0 = U384.modmul(x0, z1, params.p); ut.u1 = U384.modmul(x1, z0, params.p); - if (U384.cmp(ut.u0, ut.u1) == 0) { - if (U384.cmp(ut.t0, ut.t1) == 0) { + if (U384.eq(ut.u0, ut.u1)) { + if (U384.eq(ut.t0, ut.t1)) { return _twiceProj(params, x0, y0, z0); } else { return _zeroProj(); @@ -363,10 +363,10 @@ contract PECDSASHA1U384Authenticator { */ function _isOnCurve(Parameters memory params, uint256 x, uint256 y) internal view returns (bool) { if ( - U384.cmpInteger(x, 0) == 0 || - U384.cmp(x, params.p) == 0 || - U384.cmpInteger(y, 0) == 0 || - U384.cmp(y, params.p) == 0 + U384.eqInteger(x, 0) || + U384.eq(x, params.p) || + U384.eqInteger(y, 0) || + U384.eq(y, params.p) ) { return false; } @@ -376,15 +376,15 @@ contract PECDSASHA1U384Authenticator { //uint256 RHS = U384.modmul(U384.modmul(x, x, p), x, p); // x^3 --> modexp(x, 3, p) uint256 RHS = U384.modexp(x, 3, params.p); - if (U384.cmpInteger(params.a, 0) != 0) { + if (!U384.eqInteger(params.a, 0)) { RHS = U384.modadd(RHS, U384.modmul(x, params.a, params.p), params.p); // x^3 + a*x } - if (U384.cmpInteger(params.b, 0) != 0) { + if (!U384.eqInteger(params.b, 0)) { RHS = U384.modadd(RHS, params.b, params.p); // x^3 + a*x + b } - return U384.cmp(LHS, RHS) == 0; + return U384.eq(LHS, RHS); } /** @@ -418,6 +418,6 @@ contract PECDSASHA1U384Authenticator { * @dev Check if the curve is the zero curve. */ function _isZeroCurve(uint256 x0, uint256 y0) internal pure returns (bool isZero) { - return U384.cmpInteger(x0, 0) == 0 && U384.cmpInteger(y0, 0) == 0; + return U384.eqInteger(x0, 0) && U384.eqInteger(y0, 0); } } diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 08e42f8..24475c2 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -39,6 +39,18 @@ library U384 { return handlerCopy_; } + function eq(uint256 a_, uint256 b_) internal pure returns (bool eq_) { + assembly { + eq_ := and(eq(mload(a_), mload(b_)), eq(mload(add(a_, 0x20)), mload(add(b_, 0x20)))) + } + } + + function eqInteger(uint256 a_, uint256 bInteger_) internal pure returns (bool eq_) { + assembly { + eq_ := and(eq(mload(a_), 0), eq(mload(add(a_, 0x20)), bInteger_)) + } + } + function cmp(uint256 a_, uint256 b_) internal pure returns (int256 cmp_) { uint256 aWord_; uint256 bWord_; From cc56be31667ac96c3c54b364f3ccc24e65b5fb6a Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 18 Oct 2024 16:29:49 +0300 Subject: [PATCH 21/45] 26.8kk 512 its!!!!! --- .../PECDSASHA1U384Authenticator.sol | 149 +++++++++--------- contracts/utils/U384.sol | 124 ++++++++------- .../PECDSAAuthenticator.test.ts | 2 +- 3 files changed, 139 insertions(+), 136 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 46abeef..d8170a0 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -20,14 +20,14 @@ contract PECDSASHA1U384Authenticator { uint256 p; uint256 n; uint256 lowSmax; + uint256 call; } struct Inputs { - bytes challenge; - bytes r; - bytes s; - bytes x; - bytes y; + uint256 r; + uint256 s; + uint256 x; + uint256 y; } /** @@ -36,20 +36,17 @@ contract PECDSASHA1U384Authenticator { */ function authenticate( bytes memory challenge, - uint256 r, - uint256 s, - uint256 x, - uint256 y + Inputs memory inputs ) external view returns (bool) { /// @dev accept s only from the lower part of the curve // if (r == 0 || r >= n || s == 0 || s > lowSmax) { // return false; // } - r = U384.init(r); - s = U384.init(s); - x = U384.init(x); - y = U384.init(y); + inputs.r = U384.init(inputs.r); + inputs.s = U384.init(inputs.s); + inputs.x = U384.init(inputs.x); + inputs.y = U384.init(inputs.y); // brainpool256r1 parameters Parameters memory params = Parameters({ @@ -59,21 +56,22 @@ contract PECDSASHA1U384Authenticator { gy: 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997.init(), p: 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377.init(), n: 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7.init(), - lowSmax: 0x54fdabedd0f754de1f3305484ec1c6b9371dfb11ea9310141009a40e8fb729bb.init() + lowSmax: 0x54fdabedd0f754de1f3305484ec1c6b9371dfb11ea9310141009a40e8fb729bb.init(), + call: U384.initCall() }); - if (!_isOnCurve(params, x, y)) { + if (!_isOnCurve(params, inputs.x, inputs.y)) { return false; } uint256 message = uint256(uint160(challenge.sha1())).init(); - (uint256 x1, uint256 y1) = _multiplyScalar(params, params.gx, params.gy, U384.moddiv(message, s, params.n)); + (uint256 x1, uint256 y1) = _multiplyScalar(params, params.gx, params.gy, U384.moddiv(params.call, message, inputs.s, params.n)); console.log("x1y1"); console.logBytes(U384.toBytes(x1)); console.logBytes(U384.toBytes(y1)); - (uint256 x2, uint256 y2) = _multiplyScalar(params, x, y, U384.moddiv(r, s, params.n)); + (uint256 x2, uint256 y2) = _multiplyScalar(params, inputs.x, inputs.y, U384.moddiv(params.call, inputs.r, inputs.s, params.n)); console.log("x2y2"); console.logBytes(U384.toBytes(x2)); console.logBytes(U384.toBytes(y2)); @@ -89,7 +87,7 @@ contract PECDSASHA1U384Authenticator { // } // uint256 Px = _inverseMod(P[2], p); - // Px = U384.modmul(P[0], U384.modmul(Px, Px, p), p); + // Px = U384.modmul(params.call, P[0], U384.modmul(params.call, Px, Px, p), p); // return Px % n == r; @@ -175,37 +173,36 @@ contract PECDSASHA1U384Authenticator { } uint256 two = U384.init(2); - uint256 three = U384.init(3); - u = U384.modmul(y0, z0, params.p); - u = U384.modmul(u, two, params.p); + u = U384.modmul(params.call, y0, z0, params.p); + u = U384.modmul(params.call, u, two, params.p); - v = U384.modmul(u, x0, params.p); - v = U384.modmul(v, y0, params.p); - v = U384.modmul(v, two, params.p); + v = U384.modmul(params.call, u, x0, params.p); + v = U384.modmul(params.call, v, y0, params.p); + v = U384.modmul(params.call, v, two, params.p); - x0 = U384.modmul(x0, x0, params.p); - t = U384.modmul(x0, three, params.p); + x0 = U384.modmul(params.call, x0, x0, params.p); + t = U384.modmul(params.call, x0, U384.init(3), params.p); - z0 = U384.modmul(z0, z0, params.p); - z0 = U384.modmul(z0, params.a, params.p); - t = U384.modadd(t, z0, params.p); + z0 = U384.modmul(params.call, z0, z0, params.p); + z0 = U384.modmul(params.call, z0, params.a, params.p); + t = U384.modadd(params.call, t, z0, params.p); - w = U384.modmul(t, t, params.p); - x0 = U384.modmul(two, v, params.p); - w = U384.modadd(w, U384.sub(params.p, x0), params.p); + w = U384.modmul(params.call, t, t, params.p); + x0 = U384.modmul(params.call, two, v, params.p); + w = U384.modadd(params.call, w, U384.sub(params.p, x0), params.p); - x0 = U384.modadd(v, U384.sub(params.p, w), params.p); - x0 = U384.modmul(t, x0, params.p); - y0 = U384.modmul(y0, u, params.p); - y0 = U384.modmul(y0, y0, params.p); - y0 = U384.modmul(two, y0, params.p); - y1 = U384.modadd(x0, U384.sub(params.p, y0), params.p); + x0 = U384.modadd(params.call, v, U384.sub(params.p, w), params.p); + x0 = U384.modmul(params.call, t, x0, params.p); + y0 = U384.modmul(params.call, y0, u, params.p); + y0 = U384.modmul(params.call, y0, y0, params.p); + y0 = U384.modmul(params.call, two, y0, params.p); + y1 = U384.modadd(params.call, x0, U384.sub(params.p, y0), params.p); - x1 = U384.modmul(u, w, params.p); + x1 = U384.modmul(params.call, u, w, params.p); - z1 = U384.modmul(u, u, params.p); - z1 = U384.modmul(z1, u, params.p); + z1 = U384.modmul(params.call, u, u, params.p); + z1 = U384.modmul(params.call, z1, u, params.p); } struct UT { @@ -236,10 +233,10 @@ contract PECDSASHA1U384Authenticator { UT memory ut; - ut.t0 = U384.modmul(y0, z1, params.p); - ut.t1 = U384.modmul(y1, z0, params.p); - ut.u0 = U384.modmul(x0, z1, params.p); - ut.u1 = U384.modmul(x1, z0, params.p); + ut.t0 = U384.modmul(params.call, y0, z1, params.p); + ut.t1 = U384.modmul(params.call, y1, z0, params.p); + ut.u0 = U384.modmul(params.call, x0, z1, params.p); + ut.u1 = U384.modmul(params.call, x1, z0, params.p); if (U384.eq(ut.u0, ut.u1)) { if (U384.eq(ut.t0, ut.t1)) { @@ -249,7 +246,9 @@ contract PECDSASHA1U384Authenticator { } } - (x2, y2, z2) = _addProj2(params, U384.modmul(z0, z1, params.p), ut.u0, ut.u1, ut.t1, ut.t0); + uint256 v = U384.modmul(params.call, z0, z1, params.p); + + (x2, y2, z2) = _addProj2(params, v, ut.u0, ut.u1, ut.t1, ut.t0); } struct UTW { @@ -273,31 +272,31 @@ contract PECDSASHA1U384Authenticator { ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { UTW memory utw; - utw.t = U384.modadd(t0, U384.sub(params.p, t1), params.p); - utw.u = U384.modadd(u0, U384.sub(params.p, u1), params.p); + utw.t = U384.modadd(params.call, t0, U384.sub(params.p, t1), params.p); + utw.u = U384.modadd(params.call, u0, U384.sub(params.p, u1), params.p); - //u2 = U384.modmul(u, u, p); - utw.u2 = U384.modexp(utw.u, 2, params.p); + //u2 = U384.modmul(params.call, u, u, p); + utw.u2 = U384.modexp(params.call, utw.u, 2, params.p); - //w = U384.modmul(t, t, p); - utw.w = U384.modexp(utw.t, 2, params.p); + //w = U384.modmul(params.call, t, t, p); + utw.w = U384.modexp(params.call, utw.t, 2, params.p); - utw.w = U384.modmul(utw.w, v, params.p); - u1 = U384.modadd(u1, u0, params.p); - u1 = U384.modmul(u1, utw.u2, params.p); - utw.w = U384.modadd(utw.w, U384.sub(params.p, u1), params.p); + utw.w = U384.modmul(params.call, utw.w, v, params.p); + u1 = U384.modadd(params.call, u1, u0, params.p); + u1 = U384.modmul(params.call, u1, utw.u2, params.p); + utw.w = U384.modadd(params.call, utw.w, U384.sub(params.p, u1), params.p); - x2 = U384.modmul(utw.u, utw.w, params.p); + x2 = U384.modmul(params.call, utw.u, utw.w, params.p); - utw.u3 = U384.modmul(utw.u2, utw.u, params.p); - u0 = U384.modmul(u0, utw.u2, params.p); - u0 = U384.modadd(u0, U384.sub(params.p, utw.w), params.p); - utw.t = U384.modmul(utw.t, u0, params.p); - t0 = U384.modmul(t0, utw.u3, params.p); + utw.u3 = U384.modmul(params.call, utw.u2, utw.u, params.p); + u0 = U384.modmul(params.call, u0, utw.u2, params.p); + u0 = U384.modadd(params.call, u0, U384.sub(params.p, utw.w), params.p); + utw.t = U384.modmul(params.call, utw.t, u0, params.p); + t0 = U384.modmul(params.call, t0, utw.u3, params.p); - y2 = U384.modadd(utw.t, U384.sub(params.p, t0), params.p); + y2 = U384.modadd(params.call, utw.t, U384.sub(params.p, t0), params.p); - z2 = U384.modmul(utw.u3, v, params.p); + z2 = U384.modmul(params.call, utw.u3, v, params.p); } /** @@ -354,8 +353,8 @@ contract PECDSASHA1U384Authenticator { uint256 y0, uint256 z0 ) internal view returns (uint256 x1, uint256 y1) { - x1 = U384.moddiv(x0, z0, params.p); - y1 = U384.moddiv(y0, z0, params.p); + x1 = U384.moddiv(params.call, x0, z0, params.p); + y1 = U384.moddiv(params.call, y0, z0, params.p); } /** @@ -371,17 +370,17 @@ contract PECDSASHA1U384Authenticator { return false; } - //uint256 LHS = U384.modmul(y, y, p); // y^2 --> modexp(y, 2, p) - uint256 LHS = U384.modexp(y, 2, params.p); - //uint256 RHS = U384.modmul(U384.modmul(x, x, p), x, p); // x^3 --> modexp(x, 3, p) - uint256 RHS = U384.modexp(x, 3, params.p); + //uint256 LHS = U384.modmul(params.call, y, y, p); // y^2 --> modexp(params.call, y, 2, p) + uint256 LHS = U384.modexp(params.call, y, 2, params.p); + //uint256 RHS = U384.modmul(params.call, U384.modmul(params.call, x, x, p), x, p); // x^3 --> modexp(params.call, x, 3, p) + uint256 RHS = U384.modexp(params.call, x, 3, params.p); if (!U384.eqInteger(params.a, 0)) { - RHS = U384.modadd(RHS, U384.modmul(x, params.a, params.p), params.p); // x^3 + a*x + RHS = U384.modadd(params.call, RHS, U384.modmul(params.call, x, params.a, params.p), params.p); // x^3 + a*x } if (!U384.eqInteger(params.b, 0)) { - RHS = U384.modadd(RHS, params.b, params.p); // x^3 + a*x + b + RHS = U384.modadd(params.call, RHS, params.b, params.p); // x^3 + a*x + b } return U384.eq(LHS, RHS); @@ -395,9 +394,9 @@ contract PECDSASHA1U384Authenticator { uint256 x0, uint256 y0 ) internal view returns (uint256[3] memory P) { - P[2] = U384.modadd(U384.init(0), U384.init(1), params.p); - P[0] = U384.modmul(x0, P[2], params.p); - P[1] = U384.modmul(y0, P[2], params.p); + P[2] = U384.modadd(params.call, U384.init(0), U384.init(1), params.p); + P[0] = U384.modmul(params.call, x0, P[2], params.p); + P[1] = U384.modmul(params.call, y0, P[2], params.p); } /** diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 24475c2..69d4200 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -28,6 +28,10 @@ library U384 { return handler_; } + function initCall() internal pure returns (uint256 handler_) { + return _allocate(CALL_ALLOCATION); + } + function copy(uint256 handler_) internal view returns (uint256 handlerCopy_) { handlerCopy_ = _allocate(SHORT_ALLOCATION); @@ -110,20 +114,20 @@ library U384 { return 0; } - function modexp(uint256 b_, uint256 eInteger_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(CALL_ALLOCATION); + function modexp(uint256 call_, uint256 b_, uint256 eInteger_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(SHORT_ALLOCATION); assembly { - mstore(r_, 0x40) - mstore(add(0x20, r_), 0x20) - mstore(add(0x40, r_), 0x40) - mstore(add(0x60, r_), mload(b_)) - mstore(add(0x80, r_), mload(add(b_, 0x20))) - mstore(add(0xA0, r_), eInteger_) - mstore(add(0xC0, r_), mload(m_)) - mstore(add(0xE0, r_), mload(add(m_, 0x20))) - - if iszero(staticcall(gas(), 0x5, r_, 0x0100, r_, 0x40)) { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0x60, call_), mload(b_)) + mstore(add(0x80, call_), mload(add(b_, 0x20))) + mstore(add(0xA0, call_), eInteger_) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) { revert(0, 0) } } @@ -131,20 +135,20 @@ library U384 { return r_; } - function modadd(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(CALL_ALLOCATION); + function modadd(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(SHORT_ALLOCATION); - _add(a_, b_, r_ + 0x60); + _add(a_, b_, call_ + 0x60); assembly { - mstore(r_, 0x40) - mstore(add(0x20, r_), 0x20) - mstore(add(0x40, r_), 0x40) - mstore(add(0xA0, r_), 0x01) - mstore(add(0xC0, r_), mload(m_)) - mstore(add(0xE0, r_), mload(add(m_, 0x20))) - - if iszero(staticcall(gas(), 0x5, r_, 0x0100, r_, 0x40)) { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) { revert(0, 0) } } @@ -152,26 +156,26 @@ library U384 { return r_; } - function mod(uint256 a_, uint256 m_) internal view returns (uint256 r_) { - r_ = modexp(a_, 1, m_); + function mod(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { + r_ = modexp(call_, a_, 1, m_); return r_; } - function modsub(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(CALL_ALLOCATION); + function modsub(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(SHORT_ALLOCATION); - _sub(a_, b_, r_ + 0x60); + _sub(a_, b_, call_ + 0x60); assembly { - mstore(r_, 0x40) - mstore(add(0x20, r_), 0x20) - mstore(add(0x40, r_), 0x40) - mstore(add(0xA0, r_), 0x01) - mstore(add(0xC0, r_), mload(m_)) - mstore(add(0xE0, r_), mload(add(m_, 0x20))) - - if iszero(staticcall(gas(), 0x5, r_, 0x0100, r_, 0x40)) { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) { revert(0, 0) } } @@ -179,20 +183,20 @@ library U384 { return r_; } - function modmul(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(CALL_ALLOCATION); + function modmul(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(LONG_ALLOCATION); - _mul(a_, b_, r_ + 0x60); + _mul(a_, b_, call_ + 0x60); assembly { - mstore(r_, 0x60) - mstore(add(0x20, r_), 0x20) - mstore(add(0x40, r_), 0x40) - mstore(add(0xC0, r_), 0x01) - mstore(add(0xE0, r_), mload(m_)) - mstore(add(0x0100, r_), mload(add(m_, 0x20))) - - if iszero(staticcall(gas(), 0x5, r_, 0x0120, r_, 0x40)) { + mstore(call_, 0x60) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xC0, call_), 0x01) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) { revert(0, 0) } } @@ -200,28 +204,28 @@ library U384 { return r_; } - function moddiv(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(CALL_ALLOCATION); + function moddiv(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(SHORT_ALLOCATION); uint256 two_ = init(2); - _sub(m_, two_, r_ + 0xA0); + _sub(m_, two_, call_ + 0xA0); assembly { - mstore(r_, 0x40) - mstore(add(0x20, r_), 0x40) - mstore(add(0x40, r_), 0x40) - mstore(add(0x60, r_), mload(b_)) - mstore(add(0x80, r_), mload(add(b_, 0x20))) - mstore(add(0xE0, r_), mload(m_)) - mstore(add(0x0100, r_), mload(add(m_, 0x20))) - - if iszero(staticcall(gas(), 0x5, r_, 0x0120, r_, 0x40)) { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x40) + mstore(add(0x40, call_), 0x40) + mstore(add(0x60, call_), mload(b_)) + mstore(add(0x80, call_), mload(add(b_, 0x20))) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) + + if iszero(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) { revert(0, 0) } } - return modmul(a_, r_, m_); + return modmul(call_, a_, r_, m_); } function add(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts index 54144be..9b260c9 100644 --- a/test/passport/authenticators/PECDSAAuthenticator.test.ts +++ b/test/passport/authenticators/PECDSAAuthenticator.test.ts @@ -75,7 +75,7 @@ describe("PECDSAAuthenticator", () => { const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; //await authSha2New.forTest(y); - expect(await authU384.authenticate(challenge, r, s, x, y)).to.be.false; + expect(await authU384.authenticate(challenge, { r, s, x, y })).to.be.false; // console.log(gx, gy, modmul(BigInt(ethers.sha256(challenge)), sInv, n)); From cd41bade044cad6efb6e59653ba4f579d456e34a Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 18 Oct 2024 17:02:58 +0300 Subject: [PATCH 22/45] 44kk 768 its! --- .../PECDSASHA1U384Authenticator.sol | 39 ++++++++++++------- contracts/utils/U384.sol | 5 ++- .../PECDSAAuthenticator.test.ts | 24 ++++++------ 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index d8170a0..d7d81d1 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -24,6 +24,13 @@ contract PECDSASHA1U384Authenticator { } struct Inputs { + bytes r; + bytes s; + bytes x; + bytes y; + } + + struct _Inputs { uint256 r; uint256 s; uint256 x; @@ -43,35 +50,37 @@ contract PECDSASHA1U384Authenticator { // return false; // } - inputs.r = U384.init(inputs.r); - inputs.s = U384.init(inputs.s); - inputs.x = U384.init(inputs.x); - inputs.y = U384.init(inputs.y); + _Inputs memory _inputs; + + _inputs.r = U384.init(inputs.r); + _inputs.s = U384.init(inputs.s); + _inputs.x = U384.init(inputs.x); + _inputs.y = U384.init(inputs.y); // brainpool256r1 parameters Parameters memory params = Parameters({ - a: 0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9.init(), - b: 0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6.init(), - gx: 0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262.init(), - gy: 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997.init(), - p: 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377.init(), - n: 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7.init(), - lowSmax: 0x54fdabedd0f754de1f3305484ec1c6b9371dfb11ea9310141009a40e8fb729bb.init(), + a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC".init(), + b: hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF".init(), + gx: hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7".init(), + gy: hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f".init(), + p: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF".init(), + n: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973".init(), + lowSmax: hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b".init(), call: U384.initCall() }); - if (!_isOnCurve(params, inputs.x, inputs.y)) { + if (!_isOnCurve(params, _inputs.x, _inputs.y)) { return false; } - uint256 message = uint256(uint160(challenge.sha1())).init(); + uint256 message = uint256(sha256(challenge)).init(); - (uint256 x1, uint256 y1) = _multiplyScalar(params, params.gx, params.gy, U384.moddiv(params.call, message, inputs.s, params.n)); + (uint256 x1, uint256 y1) = _multiplyScalar(params, params.gx, params.gy, U384.moddiv(params.call, message, _inputs.s, params.n)); console.log("x1y1"); console.logBytes(U384.toBytes(x1)); console.logBytes(U384.toBytes(y1)); - (uint256 x2, uint256 y2) = _multiplyScalar(params, inputs.x, inputs.y, U384.moddiv(params.call, inputs.r, inputs.s, params.n)); + (uint256 x2, uint256 y2) = _multiplyScalar(params, _inputs.x, _inputs.y, U384.moddiv(params.call, _inputs.r, _inputs.s, params.n)); console.log("x2y2"); console.logBytes(U384.toBytes(x2)); console.logBytes(U384.toBytes(y2)); diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 69d4200..5503aa6 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -21,8 +21,9 @@ library U384 { handler_ = _allocate(SHORT_ALLOCATION); assembly { - mstore(handler_, mload(add(from_, 0x20))) - mstore(add(handler_, 0x20), mload(add(from_, 0x40))) + mstore(handler_, 0x00) + mstore(add(handler_, 0x10), mload(add(from_, 0x20))) + mstore(add(handler_, 0x20), mload(add(from_, 0x30))) } return handler_; diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts index 9b260c9..7cd95a3 100644 --- a/test/passport/authenticators/PECDSAAuthenticator.test.ts +++ b/test/passport/authenticators/PECDSAAuthenticator.test.ts @@ -59,20 +59,20 @@ describe("PECDSAAuthenticator", () => { }); it.only("should authenticate passport - secp384r1 & sha2 new", async () => { - // const challenge = - // "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; - // - // const r = "0x" + "3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63".padStart(128, "0"); - // const s = "0x" + "f1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd".padStart(128, "0"); - // const x = "0x" + "56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6".padStart(128, "0"); - // const y = "0x" + "1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a".padStart(128, "0"); + const challenge = + "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; - const challenge = "0xe7938ea62eb1980a"; + const r = "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63"; + const s = "0xf1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd"; + const x = "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6"; + const y = "0x1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; - const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; - const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; - const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; - const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; + // const challenge = "0xe7938ea62eb1980a"; + // + // const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; + // const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; + // const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; + // const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; //await authSha2New.forTest(y); expect(await authU384.authenticate(challenge, { r, s, x, y })).to.be.false; From 4ab25856c58d197e6a9c30c296a155c2fa3d472b Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Fri, 18 Oct 2024 18:24:42 +0300 Subject: [PATCH 23/45] 38.1kk --- .../PECDSASHA1U384Authenticator.sol | 252 ++++++++++-------- contracts/utils/U384.sol | 30 +-- 2 files changed, 145 insertions(+), 137 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index d7d81d1..01aca76 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -59,28 +59,45 @@ contract PECDSASHA1U384Authenticator { // brainpool256r1 parameters Parameters memory params = Parameters({ - a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC".init(), - b: hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF".init(), - gx: hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7".init(), - gy: hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f".init(), - p: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF".init(), - n: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973".init(), - lowSmax: hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b".init(), + a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" + .init(), + b: hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF" + .init(), + gx: hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" + .init(), + gy: hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" + .init(), + p: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" + .init(), + n: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" + .init(), + lowSmax: hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" + .init(), call: U384.initCall() }); - if (!_isOnCurve(params, _inputs.x, _inputs.y)) { + if (!_isOnCurve(params.call, params.p, params.a, params.b, _inputs.x, _inputs.y)) { return false; } uint256 message = uint256(sha256(challenge)).init(); - (uint256 x1, uint256 y1) = _multiplyScalar(params, params.gx, params.gy, U384.moddiv(params.call, message, _inputs.s, params.n)); + (uint256 x1, uint256 y1) = _multiplyScalar( + params, + params.gx, + params.gy, + U384.moddiv(params.call, message, _inputs.s, params.n) + ); console.log("x1y1"); console.logBytes(U384.toBytes(x1)); console.logBytes(U384.toBytes(y1)); - (uint256 x2, uint256 y2) = _multiplyScalar(params, _inputs.x, _inputs.y, U384.moddiv(params.call, _inputs.r, _inputs.s, params.n)); + (uint256 x2, uint256 y2) = _multiplyScalar( + params, + _inputs.x, + _inputs.y, + U384.moddiv(params.call, _inputs.r, _inputs.s, params.n) + ); console.log("x2y2"); console.logBytes(U384.toBytes(x2)); console.logBytes(U384.toBytes(y2)); @@ -117,7 +134,7 @@ contract PECDSASHA1U384Authenticator { } else if (U384.eqInteger(scalar, 1)) { return (x0, y0); } else if (U384.eqInteger(scalar, 2)) { - return _twice(params, x0, y0); + return _twice(params.call, params.p, params.a, x0, y0); } uint256 base2X = x0; @@ -146,7 +163,14 @@ contract PECDSASHA1U384Authenticator { highBits_ >>= 1; while (lowBits_ > 0 || highBits_ > 0) { - (base2X, base2Y, base2Z) = _twiceProj(params, base2X, base2Y, base2Z); + (base2X, base2Y, base2Z) = _twiceProj( + params.call, + params.p, + params.a, + base2X, + base2Y, + base2Z + ); if (lowBits_ % 2 == 1) { (x1, y1, z1) = _addProj(params, base2X, base2Y, base2Z, x1, y1, z1); @@ -159,7 +183,7 @@ contract PECDSASHA1U384Authenticator { //console.log("gas", 300_000_000 - gasleft()); } - return _toAffinePoint(params, x1, y1, z1); + return _toAffinePoint(params.call, params.p, x1, y1, z1); } /** @@ -167,58 +191,51 @@ contract PECDSASHA1U384Authenticator { * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates */ function _twiceProj( - Parameters memory params, + uint256 call, + uint256 p, + uint256 a, uint256 x0, uint256 y0, uint256 z0 ) internal view returns (uint256 x1, uint256 y1, uint256 z1) { - uint256 t; - uint256 u; - uint256 v; - uint256 w; - if (_isZeroCurve(x0, y0)) { return _zeroProj(); } + uint256 u; uint256 two = U384.init(2); - u = U384.modmul(params.call, y0, z0, params.p); - u = U384.modmul(params.call, u, two, params.p); + u = U384.modmul(call, y0, z0, p); + u = U384.modmul(call, u, two, p); - v = U384.modmul(params.call, u, x0, params.p); - v = U384.modmul(params.call, v, y0, params.p); - v = U384.modmul(params.call, v, two, params.p); + x1 = U384.modmul(call, u, x0, p); + x1 = U384.modmul(call, x1, y0, p); + x1 = U384.modmul(call, x1, two, p); - x0 = U384.modmul(params.call, x0, x0, params.p); - t = U384.modmul(params.call, x0, U384.init(3), params.p); + x0 = U384.modexp(call, x0, 2, p); - z0 = U384.modmul(params.call, z0, z0, params.p); - z0 = U384.modmul(params.call, z0, params.a, params.p); - t = U384.modadd(params.call, t, z0, params.p); + y1 = U384.modmul(call, x0, U384.init(3), p); - w = U384.modmul(params.call, t, t, params.p); - x0 = U384.modmul(params.call, two, v, params.p); - w = U384.modadd(params.call, w, U384.sub(params.p, x0), params.p); + z0 = U384.modexp(call, z0, 2, p); + z0 = U384.modmul(call, z0, a, p); + y1 = U384.modadd(call, y1, z0, p); - x0 = U384.modadd(params.call, v, U384.sub(params.p, w), params.p); - x0 = U384.modmul(params.call, t, x0, params.p); - y0 = U384.modmul(params.call, y0, u, params.p); - y0 = U384.modmul(params.call, y0, y0, params.p); - y0 = U384.modmul(params.call, two, y0, params.p); - y1 = U384.modadd(params.call, x0, U384.sub(params.p, y0), params.p); + z1 = U384.modexp(call, y1, 2, p); + x0 = U384.modmul(call, two, x1, p); + z1 = U384.modadd(call, z1, U384.sub(p, x0), p); - x1 = U384.modmul(params.call, u, w, params.p); + x0 = U384.modadd(call, x1, U384.sub(p, z1), p); + x0 = U384.modmul(call, y1, x0, p); - z1 = U384.modmul(params.call, u, u, params.p); - z1 = U384.modmul(params.call, z1, u, params.p); - } + y0 = U384.modmul(call, y0, u, p); + y0 = U384.modexp(call, y0, 2, p); + y0 = U384.modmul(call, two, y0, p); + y1 = U384.modadd(call, x0, U384.sub(p, y0), p); + + x1 = U384.modmul(call, u, z1, p); - struct UT { - uint256 u0; - uint256 u1; - uint256 t0; - uint256 t1; + z1 = U384.modexp(call, u, 2, p); + z1 = U384.modmul(call, z1, u, p); } /** @@ -234,78 +251,71 @@ contract PECDSASHA1U384Authenticator { uint256 y1, uint256 z1 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { + uint256 call = params.call; + uint256 p = params.p; + if (_isZeroCurve(x0, y0)) { return (x1, y1, z1); } else if (_isZeroCurve(x1, y1)) { return (x0, y0, z0); } - UT memory ut; + x2 = U384.modmul(call, y0, z1, p); + y2 = U384.modmul(call, y1, z0, p); + z2 = U384.modmul(call, x0, z1, p); + y1 = U384.modmul(call, x1, z0, p); - ut.t0 = U384.modmul(params.call, y0, z1, params.p); - ut.t1 = U384.modmul(params.call, y1, z0, params.p); - ut.u0 = U384.modmul(params.call, x0, z1, params.p); - ut.u1 = U384.modmul(params.call, x1, z0, params.p); - - if (U384.eq(ut.u0, ut.u1)) { - if (U384.eq(ut.t0, ut.t1)) { - return _twiceProj(params, x0, y0, z0); + if (U384.eq(z2, y1)) { + if (U384.eq(x2, y2)) { + return _twiceProj(call, p, params.a, x0, y0, z0); } else { return _zeroProj(); } } - uint256 v = U384.modmul(params.call, z0, z1, params.p); - - (x2, y2, z2) = _addProj2(params, v, ut.u0, ut.u1, ut.t1, ut.t0); - } + uint256 v = U384.modmul(call, z0, z1, p); - struct UTW { - uint256 u; - uint256 u2; - uint256 u3; - uint256 w; - uint256 t; + return _addProj2(call, p, v, z2, y1, y2, x2); } /** * @dev Helper function that splits addProj to avoid too many local variables. */ function _addProj2( - Parameters memory params, + uint256 call, + uint256 p, uint256 v, uint256 u0, uint256 u1, uint256 t1, uint256 t0 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { - UTW memory utw; + uint256 u2; + uint256 u3; - utw.t = U384.modadd(params.call, t0, U384.sub(params.p, t1), params.p); - utw.u = U384.modadd(params.call, u0, U384.sub(params.p, u1), params.p); + y2 = U384.modadd(call, t0, U384.sub(p, t1), p); + x2 = U384.modadd(call, u0, U384.sub(p, u1), p); + u2 = U384.modexp(call, x2, 2, p); - //u2 = U384.modmul(params.call, u, u, p); - utw.u2 = U384.modexp(params.call, utw.u, 2, params.p); + z2 = U384.modexp(call, y2, 2, p); - //w = U384.modmul(params.call, t, t, p); - utw.w = U384.modexp(params.call, utw.t, 2, params.p); + z2 = U384.modmul(call, z2, v, p); + u1 = U384.modadd(call, u1, u0, p); + u1 = U384.modmul(call, u1, u2, p); + z2 = U384.modadd(call, z2, U384.sub(p, u1), p); - utw.w = U384.modmul(params.call, utw.w, v, params.p); - u1 = U384.modadd(params.call, u1, u0, params.p); - u1 = U384.modmul(params.call, u1, utw.u2, params.p); - utw.w = U384.modadd(params.call, utw.w, U384.sub(params.p, u1), params.p); + u3 = U384.modmul(call, u2, x2, p); - x2 = U384.modmul(params.call, utw.u, utw.w, params.p); + x2 = U384.modmul(call, x2, z2, p); - utw.u3 = U384.modmul(params.call, utw.u2, utw.u, params.p); - u0 = U384.modmul(params.call, u0, utw.u2, params.p); - u0 = U384.modadd(params.call, u0, U384.sub(params.p, utw.w), params.p); - utw.t = U384.modmul(params.call, utw.t, u0, params.p); - t0 = U384.modmul(params.call, t0, utw.u3, params.p); + u0 = U384.modmul(call, u0, u2, p); + u0 = U384.modadd(call, u0, U384.sub(p, z2), p); + y2 = U384.modmul(call, y2, u0, p); + t0 = U384.modmul(call, t0, u3, p); - y2 = U384.modadd(params.call, utw.t, U384.sub(params.p, t0), params.p); + y2 = U384.modadd(call, y2, U384.sub(p, t0), p); - z2 = U384.modmul(params.call, utw.u3, v, params.p); + z2 = U384.modmul(call, u3, v, p); } /** @@ -322,18 +332,24 @@ contract PECDSASHA1U384Authenticator { (x0, y0, z0) = _addProj(params, x0, y0, U384.init(1), x1, y1, U384.init(1)); - return _toAffinePoint(params,x0, y0, z0); + return _toAffinePoint(params.call, params.p, x0, y0, z0); } /** * @dev Double an elliptic curve point in affine coordinates. */ - function _twice(Parameters memory params, uint256 x0, uint256 y0) internal view returns (uint256, uint256) { + function _twice( + uint256 call, + uint256 p, + uint256 a, + uint256 x0, + uint256 y0 + ) internal view returns (uint256, uint256) { uint256 z0; - (x0, y0, z0) = _twiceProj(params, x0, y0, U384.init(1)); + (x0, y0, z0) = _twiceProj(call, p, a, x0, y0, U384.init(1)); - return _toAffinePoint(params,x0, y0, z0); + return _toAffinePoint(call, p, x0, y0, z0); } /** @@ -350,46 +366,47 @@ contract PECDSASHA1U384Authenticator { uint256 y; (x, y) = _add(params, x1, y1, x2, y2); - P = _toProjectivePoint(params,x, y); + P = _toProjectivePoint(params.call, params.p, x, y); } /** * @dev Transform from projective to affine coordinates. */ function _toAffinePoint( - Parameters memory params, + uint256 call, + uint256 p, uint256 x0, uint256 y0, uint256 z0 ) internal view returns (uint256 x1, uint256 y1) { - x1 = U384.moddiv(params.call, x0, z0, params.p); - y1 = U384.moddiv(params.call, y0, z0, params.p); + x1 = U384.moddiv(call, x0, z0, p); + y1 = U384.moddiv(call, y0, z0, p); } /** * @dev Check if a point in affine coordinates is on the curve. */ - function _isOnCurve(Parameters memory params, uint256 x, uint256 y) internal view returns (bool) { - if ( - U384.eqInteger(x, 0) || - U384.eq(x, params.p) || - U384.eqInteger(y, 0) || - U384.eq(y, params.p) - ) { - return false; - } - - //uint256 LHS = U384.modmul(params.call, y, y, p); // y^2 --> modexp(params.call, y, 2, p) - uint256 LHS = U384.modexp(params.call, y, 2, params.p); - //uint256 RHS = U384.modmul(params.call, U384.modmul(params.call, x, x, p), x, p); // x^3 --> modexp(params.call, x, 3, p) - uint256 RHS = U384.modexp(params.call, x, 3, params.p); - - if (!U384.eqInteger(params.a, 0)) { - RHS = U384.modadd(params.call, RHS, U384.modmul(params.call, x, params.a, params.p), params.p); // x^3 + a*x + function _isOnCurve( + uint256 call, + uint256 p, + uint256 a, + uint256 b, + uint256 x, + uint256 y + ) internal view returns (bool) { + if (U384.eqInteger(x, 0) || U384.eq(x, p) || U384.eqInteger(y, 0) || U384.eq(y, p)) { + return false; + } + + uint256 LHS = U384.modexp(call, y, 2, p); + uint256 RHS = U384.modexp(call, x, 3, p); + + if (!U384.eqInteger(a, 0)) { + RHS = U384.modadd(call, RHS, U384.modmul(call, x, a, p), p); // x^3 + a*x } - if (!U384.eqInteger(params.b, 0)) { - RHS = U384.modadd(params.call, RHS, params.b, params.p); // x^3 + a*x + b + if (!U384.eqInteger(b, 0)) { + RHS = U384.modadd(call, RHS, b, p); // x^3 + a*x + b } return U384.eq(LHS, RHS); @@ -399,13 +416,14 @@ contract PECDSASHA1U384Authenticator { * @dev Transform affine coordinates into projective coordinates. */ function _toProjectivePoint( - Parameters memory params, + uint256 call, + uint256 p, uint256 x0, uint256 y0 ) internal view returns (uint256[3] memory P) { - P[2] = U384.modadd(params.call, U384.init(0), U384.init(1), params.p); - P[0] = U384.modmul(params.call, x0, P[2], params.p); - P[1] = U384.modmul(params.call, y0, P[2], params.p); + P[2] = U384.init(1); + P[0] = U384.modmul(call, x0, P[2], p); + P[1] = U384.modmul(call, y0, P[2], p); } /** diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 5503aa6..8b9e522 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -17,7 +17,7 @@ library U384 { return handler_; } - function init(bytes memory from_) internal view returns (uint256 handler_) { + function init(bytes memory from_) internal pure returns (uint256 handler_) { handler_ = _allocate(SHORT_ALLOCATION); assembly { @@ -33,7 +33,7 @@ library U384 { return _allocate(CALL_ALLOCATION); } - function copy(uint256 handler_) internal view returns (uint256 handlerCopy_) { + function copy(uint256 handler_) internal pure returns (uint256 handlerCopy_) { handlerCopy_ = _allocate(SHORT_ALLOCATION); assembly { @@ -128,9 +128,7 @@ library U384 { mstore(add(0xC0, call_), mload(m_)) mstore(add(0xE0, call_), mload(add(m_, 0x20))) - if iszero(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) { - revert(0, 0) - } + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) } return r_; @@ -149,9 +147,7 @@ library U384 { mstore(add(0xC0, call_), mload(m_)) mstore(add(0xE0, call_), mload(add(m_, 0x20))) - if iszero(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) { - revert(0, 0) - } + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) } return r_; @@ -176,9 +172,7 @@ library U384 { mstore(add(0xC0, call_), mload(m_)) mstore(add(0xE0, call_), mload(add(m_, 0x20))) - if iszero(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) { - revert(0, 0) - } + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) } return r_; @@ -197,9 +191,7 @@ library U384 { mstore(add(0xE0, call_), mload(m_)) mstore(add(0x0100, call_), mload(add(m_, 0x20))) - if iszero(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) { - revert(0, 0) - } + pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) } return r_; @@ -221,9 +213,7 @@ library U384 { mstore(add(0xE0, call_), mload(m_)) mstore(add(0x0100, call_), mload(add(m_, 0x20))) - if iszero(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) { - revert(0, 0) - } + pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) } return modmul(call_, a_, r_, m_); @@ -324,7 +314,7 @@ library U384 { // r3 current_ := add(shl(128, curry_), shr(128, current_)) - curry_ := 0 + curry_ := callvalue() // equals := 0 but less expensive temp_ := mul(a0_, b2_) current_ := add(current_, temp_) @@ -342,7 +332,7 @@ library U384 { // r2 current_ := add(shl(128, curry_), shr(128, current_)) - curry_ := 0 + curry_ := callvalue() temp_ := mul(a0_, b1_) current_ := add(current_, temp_) @@ -356,7 +346,7 @@ library U384 { // r1 current_ := add(shl(128, curry_), shr(128, current_)) - curry_ := 0 + curry_ := callvalue() temp_ := mul(a0_, b0_) current_ := add(current_, temp_) From 5f502b59e5dfc912599ed3e96b63ed78869b29f3 Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Fri, 18 Oct 2024 18:46:23 +0300 Subject: [PATCH 24/45] 38kk --- .../PECDSASHA1U384Authenticator.sol | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 01aca76..5baf386 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -102,7 +102,15 @@ contract PECDSASHA1U384Authenticator { console.logBytes(U384.toBytes(x2)); console.logBytes(U384.toBytes(y2)); - uint256[3] memory P = _addAndReturnProjectivePoint(params, x1, y1, x2, y2); + uint256[3] memory P = _addAndReturnProjectivePoint( + params.call, + params.p, + params.a, + x1, + y1, + x2, + y2 + ); console.logBytes(P[0].toBytes()); console.logBytes(P[1].toBytes()); @@ -150,7 +158,7 @@ contract PECDSASHA1U384Authenticator { lowBits_ := mload(add(scalar, 0x20)) } - if (lowBits_ % 2 == 0) { + if (lowBits_ & 1 == 0) { x1 = U384.init(0); y1 = U384.init(0); } else { @@ -172,15 +180,25 @@ contract PECDSASHA1U384Authenticator { base2Z ); - if (lowBits_ % 2 == 1) { - (x1, y1, z1) = _addProj(params, base2X, base2Y, base2Z, x1, y1, z1); + if (lowBits_ & 1 == 1) { + (x1, y1, z1) = _addProj( + params.call, + params.p, + params.a, + base2X, + base2Y, + base2Z, + x1, + y1, + z1 + ); } lowBits_ >>= 1; lowBits_ |= highBits_ << 255; highBits_ >>= 1; - //console.log("gas", 300_000_000 - gasleft()); + // console.log("gas", 300_000_000 - gasleft()); } return _toAffinePoint(params.call, params.p, x1, y1, z1); @@ -243,7 +261,9 @@ contract PECDSASHA1U384Authenticator { * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates */ function _addProj( - Parameters memory params, + uint256 call, + uint256 p, + uint256 a, uint256 x0, uint256 y0, uint256 z0, @@ -251,9 +271,6 @@ contract PECDSASHA1U384Authenticator { uint256 y1, uint256 z1 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { - uint256 call = params.call; - uint256 p = params.p; - if (_isZeroCurve(x0, y0)) { return (x1, y1, z1); } else if (_isZeroCurve(x1, y1)) { @@ -267,7 +284,7 @@ contract PECDSASHA1U384Authenticator { if (U384.eq(z2, y1)) { if (U384.eq(x2, y2)) { - return _twiceProj(call, p, params.a, x0, y0, z0); + return _twiceProj(call, p, a, x0, y0, z0); } else { return _zeroProj(); } @@ -322,7 +339,9 @@ contract PECDSASHA1U384Authenticator { * @dev Add two elliptic curve points in affine coordinates. */ function _add( - Parameters memory params, + uint256 call, + uint256 p, + uint256 a, uint256 x0, uint256 y0, uint256 x1, @@ -330,9 +349,9 @@ contract PECDSASHA1U384Authenticator { ) internal view returns (uint256, uint256) { uint256 z0; - (x0, y0, z0) = _addProj(params, x0, y0, U384.init(1), x1, y1, U384.init(1)); + (x0, y0, z0) = _addProj(call, p, a, x0, y0, U384.init(1), x1, y1, U384.init(1)); - return _toAffinePoint(params.call, params.p, x0, y0, z0); + return _toAffinePoint(call, p, x0, y0, z0); } /** @@ -356,7 +375,9 @@ contract PECDSASHA1U384Authenticator { * @dev Add two points in affine coordinates and return projective point. */ function _addAndReturnProjectivePoint( - Parameters memory params, + uint256 call, + uint256 p, + uint256 a, uint256 x1, uint256 y1, uint256 x2, @@ -365,8 +386,8 @@ contract PECDSASHA1U384Authenticator { uint256 x; uint256 y; - (x, y) = _add(params, x1, y1, x2, y2); - P = _toProjectivePoint(params.call, params.p, x, y); + (x, y) = _add(call, p, a, x1, y1, x2, y2); + return _toProjectivePoint(call, p, x, y); } /** From 3283496df69459970304c7c4ee7495a4f5b72866 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Sat, 19 Oct 2024 02:40:17 +0300 Subject: [PATCH 25/45] 34.8kk shl1 --- .../PECDSASHA1U384Authenticator.sol | 9 +++---- contracts/utils/U384.sol | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 5baf386..184f323 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -221,14 +221,13 @@ contract PECDSASHA1U384Authenticator { } uint256 u; - uint256 two = U384.init(2); u = U384.modmul(call, y0, z0, p); - u = U384.modmul(call, u, two, p); + u = U384.modshl1(call, u, p); x1 = U384.modmul(call, u, x0, p); x1 = U384.modmul(call, x1, y0, p); - x1 = U384.modmul(call, x1, two, p); + x1 = U384.modshl1(call, x1, p); x0 = U384.modexp(call, x0, 2, p); @@ -239,7 +238,7 @@ contract PECDSASHA1U384Authenticator { y1 = U384.modadd(call, y1, z0, p); z1 = U384.modexp(call, y1, 2, p); - x0 = U384.modmul(call, two, x1, p); + x0 = U384.modshl1(call, x1, p); z1 = U384.modadd(call, z1, U384.sub(p, x0), p); x0 = U384.modadd(call, x1, U384.sub(p, z1), p); @@ -247,7 +246,7 @@ contract PECDSASHA1U384Authenticator { y0 = U384.modmul(call, y0, u, p); y0 = U384.modexp(call, y0, 2, p); - y0 = U384.modmul(call, two, y0, p); + y0 = U384.modshl1(call, y0, p); y1 = U384.modadd(call, x0, U384.sub(p, y0), p); x1 = U384.modmul(call, u, z1, p); diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 8b9e522..a46317e 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -249,6 +249,33 @@ library U384 { return bytes_; } + function modshl1(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(SHORT_ALLOCATION); + + _shl1(a_, m_, call_ + 0x60); + + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) + } + } + + function _shl1(uint256 a_, uint256 m_, uint256 r_) internal view { + assembly { + let a0_ := mload(a_) + let a1_ := mload(add(a_, 0x20)) + + mstore(r_, or(shl(1, a0_), shr(255, a1_))) + mstore(add(r_, 0x20), shl(1, a1_)) + } + } + function _add(uint256 a_, uint256 b_, uint256 r_) private pure { assembly { let aWord_ := mload(add(a_, 0x20)) From be13993e10df301b993aa1a053781001a22fa19b Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Sat, 19 Oct 2024 03:27:52 +0300 Subject: [PATCH 26/45] 32.9kk --- contracts/utils/U384.sol | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index a46317e..0ce0f20 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -306,25 +306,17 @@ library U384 { function _mul(uint256 a_, uint256 b_, uint256 r_) private view { assembly { - function high128(x) -> y { - y := shr(128, x) - } - - function low128(x) -> y { - y := and(x, 0xffffffffffffffffffffffffffffffff) - } - let a0_ := mload(a_) - let a1_ := high128(mload(add(a_, 0x20))) - let a2_ := low128(mload(add(a_, 0x20))) + let a1_ := shr(128, mload(add(a_, 0x20))) + let a2_ := and(mload(add(a_, 0x20)), 0xffffffffffffffffffffffffffffffff) let b0_ := mload(b_) - let b1_ := high128(mload(add(b_, 0x20))) - let b2_ := low128(mload(add(b_, 0x20))) + let b1_ := shr(128, mload(add(b_, 0x20))) + let b2_ := and(mload(add(b_, 0x20)), 0xffffffffffffffffffffffffffffffff) // r5 let current_ := mul(a2_, b2_) - let r5_ := low128(current_) + let r0_ := and(current_, 0xffffffffffffffffffffffffffffffff) // r4 current_ := shr(128, current_) @@ -337,7 +329,7 @@ library U384 { current_ := add(current_, temp_) curry_ := add(curry_, lt(current_, temp_)) - let r4_ := low128(current_) + mstore(add(r_, 0x40), add(shl(128, current_), r0_)) // r3 current_ := add(shl(128, curry_), shr(128, current_)) @@ -355,7 +347,7 @@ library U384 { current_ := add(current_, temp_) curry_ := add(curry_, lt(current_, temp_)) - let r3_ := low128(current_) + r0_ := and(current_, 0xffffffffffffffffffffffffffffffff) // r2 current_ := add(shl(128, curry_), shr(128, current_)) @@ -369,7 +361,7 @@ library U384 { current_ := add(current_, temp_) curry_ := add(curry_, lt(current_, temp_)) - let r2_ := low128(current_) + mstore(add(r_, 0x20), add(shl(128, current_), r0_)) // r1 current_ := add(shl(128, curry_), shr(128, current_)) @@ -379,14 +371,7 @@ library U384 { current_ := add(current_, temp_) curry_ := lt(current_, temp_) - let r1_ := low128(current_) - - // r0 - let r0_ := shr(128, current_) - - mstore(r_, add(shl(128, r0_), r1_)) - mstore(add(r_, 0x20), add(shl(128, r2_), r3_)) - mstore(add(r_, 0x40), add(shl(128, r4_), r5_)) + mstore(r_, current_) } } From 615edbdd8f3a0332a90024283bd6100d01ce1855 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Mon, 21 Oct 2024 02:20:08 +0300 Subject: [PATCH 27/45] ez 26.5kk can be even less if using references --- .../PECDSASHA1U384Authenticator.sol | 39 +++++---- contracts/utils/U384.sol | 84 ++++++++++++++++++- .../PECDSAAuthenticator.test.ts | 2 +- 3 files changed, 100 insertions(+), 25 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 184f323..389f1ba 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -98,6 +98,7 @@ contract PECDSASHA1U384Authenticator { _inputs.y, U384.moddiv(params.call, _inputs.r, _inputs.s, params.n) ); + console.log("x2y2"); console.logBytes(U384.toBytes(x2)); console.logBytes(U384.toBytes(y2)); @@ -116,16 +117,14 @@ contract PECDSASHA1U384Authenticator { console.logBytes(P[1].toBytes()); console.logBytes(P[2].toBytes()); - // if (P[2] == 0) { - // return false; - // } - - // uint256 Px = _inverseMod(P[2], p); - // Px = U384.modmul(params.call, P[0], U384.modmul(params.call, Px, Px, p), p); + if (U384.eqInteger(P[2], 0)) { + return false; + } - // return Px % n == r; + uint256 Px = U384.modinv(params.call, P[2], params.p); + Px = U384.modmul(params.call, P[0], U384.modmul(params.call, Px, Px, params.p), params.p); - return true; + return U384.eq(U384.mod(params.call, Px, params.n), _inputs.r); } /** @@ -223,11 +222,11 @@ contract PECDSASHA1U384Authenticator { uint256 u; u = U384.modmul(call, y0, z0, p); - u = U384.modshl1(call, u, p); + U384.modshl1Assign(call, u, p); x1 = U384.modmul(call, u, x0, p); - x1 = U384.modmul(call, x1, y0, p); - x1 = U384.modshl1(call, x1, p); + U384.modmulAssign(call, x1, y0, p); + U384.modshl1Assign(call, x1, p); x0 = U384.modexp(call, x0, 2, p); @@ -235,14 +234,14 @@ contract PECDSASHA1U384Authenticator { z0 = U384.modexp(call, z0, 2, p); z0 = U384.modmul(call, z0, a, p); - y1 = U384.modadd(call, y1, z0, p); + U384.modaddAssign(call, y1, z0, p); z1 = U384.modexp(call, y1, 2, p); x0 = U384.modshl1(call, x1, p); - z1 = U384.modadd(call, z1, U384.sub(p, x0), p); + U384.modaddAssign(call, z1, U384.sub(p, x0), p); x0 = U384.modadd(call, x1, U384.sub(p, z1), p); - x0 = U384.modmul(call, y1, x0, p); + x0 = U384.modmul(call, x0, y1, p); y0 = U384.modmul(call, y0, u, p); y0 = U384.modexp(call, y0, 2, p); @@ -252,7 +251,7 @@ contract PECDSASHA1U384Authenticator { x1 = U384.modmul(call, u, z1, p); z1 = U384.modexp(call, u, 2, p); - z1 = U384.modmul(call, z1, u, p); + U384.modmulAssign(call, z1, u, p); } /** @@ -315,21 +314,21 @@ contract PECDSASHA1U384Authenticator { z2 = U384.modexp(call, y2, 2, p); - z2 = U384.modmul(call, z2, v, p); + U384.modmulAssign(call, z2, v, p); u1 = U384.modadd(call, u1, u0, p); u1 = U384.modmul(call, u1, u2, p); - z2 = U384.modadd(call, z2, U384.sub(p, u1), p); + U384.modaddAssign(call, z2, U384.sub(p, u1), p); u3 = U384.modmul(call, u2, x2, p); - x2 = U384.modmul(call, x2, z2, p); + U384.modmulAssign(call, x2, z2, p); u0 = U384.modmul(call, u0, u2, p); u0 = U384.modadd(call, u0, U384.sub(p, z2), p); - y2 = U384.modmul(call, y2, u0, p); + U384.modmulAssign(call, y2, u0, p); t0 = U384.modmul(call, t0, u3, p); - y2 = U384.modadd(call, y2, U384.sub(p, t0), p); + U384.modaddAssign(call, y2, U384.sub(p, t0), p); z2 = U384.modmul(call, u3, v, p); } diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 0ce0f20..7963b46 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -134,6 +134,21 @@ library U384 { return r_; } + function modexpAssign(uint256 call_, uint256 b_, uint256 eInteger_, uint256 m_) internal view { + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0x60, call_), mload(b_)) + mstore(add(0x80, call_), mload(add(b_, 0x20))) + mstore(add(0xA0, call_), eInteger_) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0100, b_, 0x40)) + } + } + function modadd(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { r_ = _allocate(SHORT_ALLOCATION); @@ -153,6 +168,21 @@ library U384 { return r_; } + function modaddAssign(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view { + _add(a_, b_, call_ + 0x60); + + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0100, a_, 0x40)) + } + } + function mod(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { r_ = modexp(call_, a_, 1, m_); @@ -179,7 +209,7 @@ library U384 { } function modmul(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(LONG_ALLOCATION); + r_ = _allocate(SHORT_ALLOCATION); _mul(a_, b_, call_ + 0x60); @@ -197,12 +227,43 @@ library U384 { return r_; } - function moddiv(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + function modmulAssign(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view { + _mul(a_, b_, call_ + 0x60); + + assembly { + mstore(call_, 0x60) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xC0, call_), 0x01) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0120, a_, 0x40)) + } + } + + function modinv(uint256 call_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { r_ = _allocate(SHORT_ALLOCATION); - uint256 two_ = init(2); + _sub(m_, init(2), call_ + 0xA0); + + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x40) + mstore(add(0x40, call_), 0x40) + mstore(add(0x60, call_), mload(b_)) + mstore(add(0x80, call_), mload(add(b_, 0x20))) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) - _sub(m_, two_, call_ + 0xA0); + pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) + } + } + + function moddiv(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { + r_ = _allocate(SHORT_ALLOCATION); + + _sub(m_, init(2), call_ + 0xA0); assembly { mstore(call_, 0x40) @@ -266,6 +327,21 @@ library U384 { } } + function modshl1Assign(uint256 call_, uint256 a_, uint256 m_) internal view { + _shl1(a_, m_, call_ + 0x60); + + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0100, a_, 0x40)) + } + } + function _shl1(uint256 a_, uint256 m_, uint256 r_) internal view { assembly { let a0_ := mload(a_) diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts index 7cd95a3..09a815e 100644 --- a/test/passport/authenticators/PECDSAAuthenticator.test.ts +++ b/test/passport/authenticators/PECDSAAuthenticator.test.ts @@ -75,7 +75,7 @@ describe("PECDSAAuthenticator", () => { // const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; //await authSha2New.forTest(y); - expect(await authU384.authenticate(challenge, { r, s, x, y })).to.be.false; + expect(await authU384.authenticate(challenge, { r, s, x, y })).to.be.true; // console.log(gx, gy, modmul(BigInt(ethers.sha256(challenge)), sInv, n)); From cf9f8f920f7a9a0ad97b5e9375ad647f1aadccb2 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Mon, 21 Oct 2024 14:14:58 +0300 Subject: [PATCH 28/45] 24kk readable --- .../PECDSASHA1U384Authenticator.sol | 53 ++++++------- contracts/utils/U384.sol | 74 +++++++++++++++++++ 2 files changed, 102 insertions(+), 25 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 389f1ba..f7649bb 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -215,42 +215,44 @@ contract PECDSASHA1U384Authenticator { uint256 y0, uint256 z0 ) internal view returns (uint256 x1, uint256 y1, uint256 z1) { + x0 = x0.copy(); + y0 = y0.copy(); + z0 = z0.copy(); + if (_isZeroCurve(x0, y0)) { return _zeroProj(); } - uint256 u; - - u = U384.modmul(call, y0, z0, p); + uint256 u = U384.modmul(call, y0, z0, p); U384.modshl1Assign(call, u, p); x1 = U384.modmul(call, u, x0, p); U384.modmulAssign(call, x1, y0, p); U384.modshl1Assign(call, x1, p); - x0 = U384.modexp(call, x0, 2, p); + U384.modexpAssign(call, x0, 2, p); y1 = U384.modmul(call, x0, U384.init(3), p); - z0 = U384.modexp(call, z0, 2, p); - z0 = U384.modmul(call, z0, a, p); + U384.modexpAssign(call, z0, 2, p); + U384.modmulAssign(call, z0, a, p); U384.modaddAssign(call, y1, z0, p); z1 = U384.modexp(call, y1, 2, p); - x0 = U384.modshl1(call, x1, p); + U384.modshl1AssignTo(call, x0, x1, p); U384.modaddAssign(call, z1, U384.sub(p, x0), p); - x0 = U384.modadd(call, x1, U384.sub(p, z1), p); - x0 = U384.modmul(call, x0, y1, p); + U384.modaddAssignTo(call, x0, x1, U384.sub(p, z1), p); + U384.modmulAssign(call, x0, y1, p); - y0 = U384.modmul(call, y0, u, p); - y0 = U384.modexp(call, y0, 2, p); - y0 = U384.modshl1(call, y0, p); - y1 = U384.modadd(call, x0, U384.sub(p, y0), p); + U384.modmulAssign(call, y0, u, p); + U384.modexpAssign(call, y0, 2, p); + U384.modshl1Assign(call, y0, p); + U384.modaddAssignTo(call, y1, x0, U384.sub(p, y0), p); - x1 = U384.modmul(call, u, z1, p); + U384.modmulAssignTo(call, x1, u, z1, p); - z1 = U384.modexp(call, u, 2, p); + U384.modexpAssignTo(call, z1, u, 2, p); U384.modmulAssign(call, z1, u, p); } @@ -305,32 +307,33 @@ contract PECDSASHA1U384Authenticator { uint256 t1, uint256 t0 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { - uint256 u2; - uint256 u3; + u0 = u0.copy(); + u1 = u1.copy(); + t0 = t0.copy(); y2 = U384.modadd(call, t0, U384.sub(p, t1), p); x2 = U384.modadd(call, u0, U384.sub(p, u1), p); - u2 = U384.modexp(call, x2, 2, p); + uint256 u2 = U384.modexp(call, x2, 2, p); z2 = U384.modexp(call, y2, 2, p); U384.modmulAssign(call, z2, v, p); - u1 = U384.modadd(call, u1, u0, p); - u1 = U384.modmul(call, u1, u2, p); + U384.modaddAssign(call, u1, u0, p); + U384.modmulAssign(call, u1, u2, p); U384.modaddAssign(call, z2, U384.sub(p, u1), p); - u3 = U384.modmul(call, u2, x2, p); + uint256 u3 = U384.modmul(call, u2, x2, p); U384.modmulAssign(call, x2, z2, p); - u0 = U384.modmul(call, u0, u2, p); - u0 = U384.modadd(call, u0, U384.sub(p, z2), p); + U384.modmulAssign(call, u0, u2, p); + U384.modaddAssign(call, u0, U384.sub(p, z2), p); U384.modmulAssign(call, y2, u0, p); - t0 = U384.modmul(call, t0, u3, p); + U384.modmulAssign(call, t0, u3, p); U384.modaddAssign(call, y2, U384.sub(p, t0), p); - z2 = U384.modmul(call, u3, v, p); + U384.modmulAssignTo(call, z2, u3, v, p); } /** diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 7963b46..890fb62 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -29,6 +29,20 @@ library U384 { return handler_; } + function assign(uint256 to_, uint256 from_) internal pure { + assembly { + mstore(to_, mload(from_)) + mstore(add(to_, 0x20), mload(add(from_, 0x20))) + } + } + + function assignInteger(uint256 to_, uint256 fromInteger_) internal pure { + assembly { + mstore(to_, 0x00) + mstore(add(to_, 0x20), fromInteger_) + } + } + function initCall() internal pure returns (uint256 handler_) { return _allocate(CALL_ALLOCATION); } @@ -149,6 +163,21 @@ library U384 { } } + function modexpAssignTo(uint256 call_, uint256 to_, uint256 b_, uint256 eInteger_, uint256 m_) internal view { + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0x60, call_), mload(b_)) + mstore(add(0x80, call_), mload(add(b_, 0x20))) + mstore(add(0xA0, call_), eInteger_) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) + } + } + function modadd(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { r_ = _allocate(SHORT_ALLOCATION); @@ -183,6 +212,21 @@ library U384 { } } + function modaddAssignTo(uint256 call_, uint256 to_, uint256 a_, uint256 b_, uint256 m_) internal view { + _add(a_, b_, call_ + 0x60); + + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) + } + } + function mod(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { r_ = modexp(call_, a_, 1, m_); @@ -242,6 +286,21 @@ library U384 { } } + function modmulAssignTo(uint256 call_, uint256 to_, uint256 a_, uint256 b_, uint256 m_) internal view { + _mul(a_, b_, call_ + 0x60); + + assembly { + mstore(call_, 0x60) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xC0, call_), 0x01) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0120, to_, 0x40)) + } + } + function modinv(uint256 call_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { r_ = _allocate(SHORT_ALLOCATION); @@ -342,6 +401,21 @@ library U384 { } } + function modshl1AssignTo(uint256 call_, uint256 to_, uint256 a_, uint256 m_) internal view { + _shl1(a_, m_, call_ + 0x60); + + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + + pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) + } + } + function _shl1(uint256 a_, uint256 m_, uint256 r_) internal view { assembly { let a0_ := mload(a_) From f5996a246ae74cd19e40c040a6381a7c8fc9fb9d Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Mon, 21 Oct 2024 17:52:30 +0300 Subject: [PATCH 29/45] 23kk --- .../PECDSASHA1U384Authenticator.sol | 59 +++++++++++++------ contracts/utils/U384.sol | 4 ++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index f7649bb..4e760d6 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -21,6 +21,7 @@ contract PECDSASHA1U384Authenticator { uint256 n; uint256 lowSmax; uint256 call; + uint256 three; } struct Inputs { @@ -73,7 +74,8 @@ contract PECDSASHA1U384Authenticator { .init(), lowSmax: hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" .init(), - call: U384.initCall() + call: U384.initCall(), + three: U384.init(3) }); if (!_isOnCurve(params.call, params.p, params.a, params.b, _inputs.x, _inputs.y)) { @@ -106,6 +108,7 @@ contract PECDSASHA1U384Authenticator { uint256[3] memory P = _addAndReturnProjectivePoint( params.call, params.p, + params.three, params.a, x1, y1, @@ -141,7 +144,7 @@ contract PECDSASHA1U384Authenticator { } else if (U384.eqInteger(scalar, 1)) { return (x0, y0); } else if (U384.eqInteger(scalar, 2)) { - return _twice(params.call, params.p, params.a, x0, y0); + return _twice(params.call, params.p, params.three, params.a, x0, y0); } uint256 base2X = x0; @@ -173,6 +176,7 @@ contract PECDSASHA1U384Authenticator { (base2X, base2Y, base2Z) = _twiceProj( params.call, params.p, + params.three, params.a, base2X, base2Y, @@ -183,6 +187,7 @@ contract PECDSASHA1U384Authenticator { (x1, y1, z1) = _addProj( params.call, params.p, + params.three, params.a, base2X, base2Y, @@ -210,6 +215,7 @@ contract PECDSASHA1U384Authenticator { function _twiceProj( uint256 call, uint256 p, + uint256 three, uint256 a, uint256 x0, uint256 y0, @@ -232,7 +238,7 @@ contract PECDSASHA1U384Authenticator { U384.modexpAssign(call, x0, 2, p); - y1 = U384.modmul(call, x0, U384.init(3), p); + y1 = U384.modmul(call, x0, three, p); U384.modexpAssign(call, z0, 2, p); U384.modmulAssign(call, z0, a, p); @@ -240,15 +246,20 @@ contract PECDSASHA1U384Authenticator { z1 = U384.modexp(call, y1, 2, p); U384.modshl1AssignTo(call, x0, x1, p); - U384.modaddAssign(call, z1, U384.sub(p, x0), p); - U384.modaddAssignTo(call, x0, x1, U384.sub(p, z1), p); + uint256 diff = U384.sub(p, x0); + U384.modaddAssign(call, z1, diff, p); + + U384.subAssignTo(diff, p, z1); + U384.modaddAssignTo(call, x0, x1, diff, p); U384.modmulAssign(call, x0, y1, p); U384.modmulAssign(call, y0, u, p); U384.modexpAssign(call, y0, 2, p); U384.modshl1Assign(call, y0, p); - U384.modaddAssignTo(call, y1, x0, U384.sub(p, y0), p); + + U384.subAssignTo(diff, p, y0); + U384.modaddAssignTo(call, y1, x0, diff, p); U384.modmulAssignTo(call, x1, u, z1, p); @@ -263,6 +274,7 @@ contract PECDSASHA1U384Authenticator { function _addProj( uint256 call, uint256 p, + uint256 three, uint256 a, uint256 x0, uint256 y0, @@ -284,15 +296,15 @@ contract PECDSASHA1U384Authenticator { if (U384.eq(z2, y1)) { if (U384.eq(x2, y2)) { - return _twiceProj(call, p, a, x0, y0, z0); + return _twiceProj(call, p, three, a, x0, y0, z0); } else { return _zeroProj(); } } - uint256 v = U384.modmul(call, z0, z1, p); + a = U384.modmul(call, z0, z1, p); - return _addProj2(call, p, v, z2, y1, y2, x2); + return _addProj2(call, p, a, z2, y1, y2, x2); } /** @@ -311,8 +323,11 @@ contract PECDSASHA1U384Authenticator { u1 = u1.copy(); t0 = t0.copy(); - y2 = U384.modadd(call, t0, U384.sub(p, t1), p); - x2 = U384.modadd(call, u0, U384.sub(p, u1), p); + uint256 diff = U384.sub(p, t1); + y2 = U384.modadd(call, t0, diff, p); + + U384.subAssignTo(diff, p, u1); + x2 = U384.modadd(call, u0, diff, p); uint256 u2 = U384.modexp(call, x2, 2, p); z2 = U384.modexp(call, y2, 2, p); @@ -320,20 +335,25 @@ contract PECDSASHA1U384Authenticator { U384.modmulAssign(call, z2, v, p); U384.modaddAssign(call, u1, u0, p); U384.modmulAssign(call, u1, u2, p); - U384.modaddAssign(call, z2, U384.sub(p, u1), p); + U384.subAssignTo(diff, p, u1); + U384.modaddAssign(call, z2, diff, p); uint256 u3 = U384.modmul(call, u2, x2, p); U384.modmulAssign(call, x2, z2, p); U384.modmulAssign(call, u0, u2, p); - U384.modaddAssign(call, u0, U384.sub(p, z2), p); + + U384.subAssignTo(diff, p, z2); + U384.modaddAssign(call, u0, diff, p); U384.modmulAssign(call, y2, u0, p); U384.modmulAssign(call, t0, u3, p); - U384.modaddAssign(call, y2, U384.sub(p, t0), p); + U384.subAssignTo(diff, p, t0); + U384.modaddAssign(call, y2, diff, p); - U384.modmulAssignTo(call, z2, u3, v, p); + U384.modmulAssign(call, u3, v, p); // stack too deep + z2 = u3; } /** @@ -342,6 +362,7 @@ contract PECDSASHA1U384Authenticator { function _add( uint256 call, uint256 p, + uint256 three, uint256 a, uint256 x0, uint256 y0, @@ -350,7 +371,7 @@ contract PECDSASHA1U384Authenticator { ) internal view returns (uint256, uint256) { uint256 z0; - (x0, y0, z0) = _addProj(call, p, a, x0, y0, U384.init(1), x1, y1, U384.init(1)); + (x0, y0, z0) = _addProj(call, p, three, a, x0, y0, U384.init(1), x1, y1, U384.init(1)); return _toAffinePoint(call, p, x0, y0, z0); } @@ -361,13 +382,14 @@ contract PECDSASHA1U384Authenticator { function _twice( uint256 call, uint256 p, + uint256 three, uint256 a, uint256 x0, uint256 y0 ) internal view returns (uint256, uint256) { uint256 z0; - (x0, y0, z0) = _twiceProj(call, p, a, x0, y0, U384.init(1)); + (x0, y0, z0) = _twiceProj(call, p, three, a, x0, y0, U384.init(1)); return _toAffinePoint(call, p, x0, y0, z0); } @@ -378,6 +400,7 @@ contract PECDSASHA1U384Authenticator { function _addAndReturnProjectivePoint( uint256 call, uint256 p, + uint256 three, uint256 a, uint256 x1, uint256 y1, @@ -387,7 +410,7 @@ contract PECDSASHA1U384Authenticator { uint256 x; uint256 y; - (x, y) = _add(call, p, a, x1, y1, x2, y2); + (x, y) = _add(call, p, three, a, x1, y1, x2, y2); return _toProjectivePoint(call, p, x, y); } diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 890fb62..e580ea3 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -355,6 +355,10 @@ library U384 { return r_; } + function subAssignTo(uint256 to_, uint256 a_, uint256 b_) internal pure returns (uint256 r_) { + _sub(a_, b_, to_); + } + function toBytes(uint256 handler_) internal pure returns (bytes memory bytes_) { uint256 bytesHandler_ = _allocate(LONG_ALLOCATION); From d3952e51c875d9c0a2e02fa81a50f40395e2eecb Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Mon, 21 Oct 2024 18:37:58 +0300 Subject: [PATCH 30/45] 21.6kk --- .../PECDSASHA1U384Authenticator.sol | 478 +++++++-------- contracts/utils/U384.sol | 555 ++++++++++-------- 2 files changed, 564 insertions(+), 469 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 4e760d6..cce0330 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -1,15 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {SHA1} from "../../utils/SHA1.sol"; import {U384} from "../../utils/U384.sol"; -import "hardhat/console.sol"; /** * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol */ contract PECDSASHA1U384Authenticator { - using SHA1 for bytes; using U384 for *; struct Parameters { @@ -46,88 +43,83 @@ contract PECDSASHA1U384Authenticator { bytes memory challenge, Inputs memory inputs ) external view returns (bool) { - /// @dev accept s only from the lower part of the curve - // if (r == 0 || r >= n || s == 0 || s > lowSmax) { - // return false; - // } - - _Inputs memory _inputs; - - _inputs.r = U384.init(inputs.r); - _inputs.s = U384.init(inputs.s); - _inputs.x = U384.init(inputs.x); - _inputs.y = U384.init(inputs.y); - - // brainpool256r1 parameters - Parameters memory params = Parameters({ - a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" - .init(), - b: hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF" - .init(), - gx: hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" - .init(), - gy: hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" - .init(), - p: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" - .init(), - n: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" - .init(), - lowSmax: hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" - .init(), - call: U384.initCall(), - three: U384.init(3) - }); - - if (!_isOnCurve(params.call, params.p, params.a, params.b, _inputs.x, _inputs.y)) { - return false; - } + unchecked { + /// @dev accept s only from the lower part of the curve + // if (r == 0 || r >= n || s == 0 || s > lowSmax) { + // return false; + // } + + _Inputs memory _inputs; + + _inputs.r = U384.init(inputs.r); + _inputs.s = U384.init(inputs.s); + _inputs.x = U384.init(inputs.x); + _inputs.y = U384.init(inputs.y); + + // brainpool256r1 parameters + Parameters memory params = Parameters({ + a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" + .init(), + b: hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF" + .init(), + gx: hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" + .init(), + gy: hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" + .init(), + p: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" + .init(), + n: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" + .init(), + lowSmax: hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" + .init(), + call: U384.initCall(), + three: U384.init(3) + }); + + if (!_isOnCurve(params.call, params.p, params.a, params.b, _inputs.x, _inputs.y)) { + return false; + } - uint256 message = uint256(sha256(challenge)).init(); - - (uint256 x1, uint256 y1) = _multiplyScalar( - params, - params.gx, - params.gy, - U384.moddiv(params.call, message, _inputs.s, params.n) - ); - console.log("x1y1"); - console.logBytes(U384.toBytes(x1)); - console.logBytes(U384.toBytes(y1)); - - (uint256 x2, uint256 y2) = _multiplyScalar( - params, - _inputs.x, - _inputs.y, - U384.moddiv(params.call, _inputs.r, _inputs.s, params.n) - ); - - console.log("x2y2"); - console.logBytes(U384.toBytes(x2)); - console.logBytes(U384.toBytes(y2)); - - uint256[3] memory P = _addAndReturnProjectivePoint( - params.call, - params.p, - params.three, - params.a, - x1, - y1, - x2, - y2 - ); - - console.logBytes(P[0].toBytes()); - console.logBytes(P[1].toBytes()); - console.logBytes(P[2].toBytes()); - - if (U384.eqInteger(P[2], 0)) { - return false; - } + uint256 message = uint256(sha256(challenge)).init(); - uint256 Px = U384.modinv(params.call, P[2], params.p); - Px = U384.modmul(params.call, P[0], U384.modmul(params.call, Px, Px, params.p), params.p); + (uint256 x1, uint256 y1) = _multiplyScalar( + params, + params.gx, + params.gy, + U384.moddiv(params.call, message, _inputs.s, params.n) + ); + (uint256 x2, uint256 y2) = _multiplyScalar( + params, + _inputs.x, + _inputs.y, + U384.moddiv(params.call, _inputs.r, _inputs.s, params.n) + ); - return U384.eq(U384.mod(params.call, Px, params.n), _inputs.r); + uint256[3] memory P = _addAndReturnProjectivePoint( + params.call, + params.p, + params.three, + params.a, + x1, + y1, + x2, + y2 + ); + + if (U384.eqInteger(P[2], 0)) { + return false; + } + + uint256 Px = U384.modinv(params.call, P[2], params.p); + Px = U384.modmul( + params.call, + P[0], + U384.modmul(params.call, Px, Px, params.p), + params.p + ); + + return U384.eq(U384.mod(params.call, Px, params.n), _inputs.r); + } } /** @@ -139,73 +131,73 @@ contract PECDSASHA1U384Authenticator { uint256 y0, uint256 scalar ) internal view returns (uint256 x1, uint256 y1) { - if (U384.eqInteger(scalar, 0)) { - return _zeroAffine(); - } else if (U384.eqInteger(scalar, 1)) { - return (x0, y0); - } else if (U384.eqInteger(scalar, 2)) { - return _twice(params.call, params.p, params.three, params.a, x0, y0); - } - - uint256 base2X = x0; - uint256 base2Y = y0; - uint256 base2Z = U384.init(1); - uint256 z1 = U384.init(1); + unchecked { + if (U384.eqInteger(scalar, 0)) { + return _zeroAffine(); + } else if (U384.eqInteger(scalar, 1)) { + return (x0, y0); + } else if (U384.eqInteger(scalar, 2)) { + return _twice(params.call, params.p, params.three, params.a, x0, y0); + } - uint256 highBits_; - uint256 lowBits_; + uint256 base2X = x0; + uint256 base2Y = y0; + uint256 base2Z = U384.init(1); + uint256 z1 = U384.init(1); - assembly { - highBits_ := mload(scalar) - lowBits_ := mload(add(scalar, 0x20)) - } + uint256 highBits_; + uint256 lowBits_; - if (lowBits_ & 1 == 0) { - x1 = U384.init(0); - y1 = U384.init(0); - } else { - x1 = U384.copy(x0); - y1 = U384.copy(y0); - } + assembly { + highBits_ := mload(scalar) + lowBits_ := mload(add(scalar, 0x20)) + } - lowBits_ >>= 1; - lowBits_ |= highBits_ << 255; - highBits_ >>= 1; + if (lowBits_ & 1 == 0) { + x1 = U384.init(0); + y1 = U384.init(0); + } else { + x1 = U384.copy(x0); + y1 = U384.copy(y0); + } - while (lowBits_ > 0 || highBits_ > 0) { - (base2X, base2Y, base2Z) = _twiceProj( - params.call, - params.p, - params.three, - params.a, - base2X, - base2Y, - base2Z - ); + lowBits_ >>= 1; + lowBits_ |= highBits_ << 255; + highBits_ >>= 1; - if (lowBits_ & 1 == 1) { - (x1, y1, z1) = _addProj( + while (lowBits_ > 0 || highBits_ > 0) { + (base2X, base2Y, base2Z) = _twiceProj( params.call, params.p, params.three, params.a, base2X, base2Y, - base2Z, - x1, - y1, - z1 + base2Z ); - } - lowBits_ >>= 1; - lowBits_ |= highBits_ << 255; - highBits_ >>= 1; + if (lowBits_ & 1 == 1) { + (x1, y1, z1) = _addProj( + params.call, + params.p, + params.three, + params.a, + base2X, + base2Y, + base2Z, + x1, + y1, + z1 + ); + } + + lowBits_ >>= 1; + lowBits_ |= highBits_ << 255; + highBits_ >>= 1; + } - // console.log("gas", 300_000_000 - gasleft()); + return _toAffinePoint(params.call, params.p, x1, y1, z1); } - - return _toAffinePoint(params.call, params.p, x1, y1, z1); } /** @@ -221,50 +213,52 @@ contract PECDSASHA1U384Authenticator { uint256 y0, uint256 z0 ) internal view returns (uint256 x1, uint256 y1, uint256 z1) { - x0 = x0.copy(); - y0 = y0.copy(); - z0 = z0.copy(); + unchecked { + x0 = x0.copy(); + y0 = y0.copy(); + z0 = z0.copy(); - if (_isZeroCurve(x0, y0)) { - return _zeroProj(); - } + if (_isZeroCurve(x0, y0)) { + return _zeroProj(); + } - uint256 u = U384.modmul(call, y0, z0, p); - U384.modshl1Assign(call, u, p); + uint256 u = U384.modmul(call, y0, z0, p); + U384.modshl1Assign(call, u, p); - x1 = U384.modmul(call, u, x0, p); - U384.modmulAssign(call, x1, y0, p); - U384.modshl1Assign(call, x1, p); + x1 = U384.modmul(call, u, x0, p); + U384.modmulAssign(call, x1, y0, p); + U384.modshl1Assign(call, x1, p); - U384.modexpAssign(call, x0, 2, p); + U384.modexpAssign(call, x0, 2, p); - y1 = U384.modmul(call, x0, three, p); + y1 = U384.modmul(call, x0, three, p); - U384.modexpAssign(call, z0, 2, p); - U384.modmulAssign(call, z0, a, p); - U384.modaddAssign(call, y1, z0, p); + U384.modexpAssign(call, z0, 2, p); + U384.modmulAssign(call, z0, a, p); + U384.modaddAssign(call, y1, z0, p); - z1 = U384.modexp(call, y1, 2, p); - U384.modshl1AssignTo(call, x0, x1, p); + z1 = U384.modexp(call, y1, 2, p); + U384.modshl1AssignTo(call, x0, x1, p); - uint256 diff = U384.sub(p, x0); - U384.modaddAssign(call, z1, diff, p); + uint256 diff = U384.sub(p, x0); + U384.modaddAssign(call, z1, diff, p); - U384.subAssignTo(diff, p, z1); - U384.modaddAssignTo(call, x0, x1, diff, p); - U384.modmulAssign(call, x0, y1, p); + U384.subAssignTo(diff, p, z1); + U384.modaddAssignTo(call, x0, x1, diff, p); + U384.modmulAssign(call, x0, y1, p); - U384.modmulAssign(call, y0, u, p); - U384.modexpAssign(call, y0, 2, p); - U384.modshl1Assign(call, y0, p); + U384.modmulAssign(call, y0, u, p); + U384.modexpAssign(call, y0, 2, p); + U384.modshl1Assign(call, y0, p); - U384.subAssignTo(diff, p, y0); - U384.modaddAssignTo(call, y1, x0, diff, p); + U384.subAssignTo(diff, p, y0); + U384.modaddAssignTo(call, y1, x0, diff, p); - U384.modmulAssignTo(call, x1, u, z1, p); + U384.modmulAssignTo(call, x1, u, z1, p); - U384.modexpAssignTo(call, z1, u, 2, p); - U384.modmulAssign(call, z1, u, p); + U384.modexpAssignTo(call, z1, u, 2, p); + U384.modmulAssign(call, z1, u, p); + } } /** @@ -283,28 +277,30 @@ contract PECDSASHA1U384Authenticator { uint256 y1, uint256 z1 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { - if (_isZeroCurve(x0, y0)) { - return (x1, y1, z1); - } else if (_isZeroCurve(x1, y1)) { - return (x0, y0, z0); - } - - x2 = U384.modmul(call, y0, z1, p); - y2 = U384.modmul(call, y1, z0, p); - z2 = U384.modmul(call, x0, z1, p); - y1 = U384.modmul(call, x1, z0, p); + unchecked { + if (_isZeroCurve(x0, y0)) { + return (x1, y1, z1); + } else if (_isZeroCurve(x1, y1)) { + return (x0, y0, z0); + } - if (U384.eq(z2, y1)) { - if (U384.eq(x2, y2)) { - return _twiceProj(call, p, three, a, x0, y0, z0); - } else { - return _zeroProj(); + x2 = U384.modmul(call, y0, z1, p); + y2 = U384.modmul(call, y1, z0, p); + z2 = U384.modmul(call, x0, z1, p); + y1 = U384.modmul(call, x1, z0, p); + + if (U384.eq(z2, y1)) { + if (U384.eq(x2, y2)) { + return _twiceProj(call, p, three, a, x0, y0, z0); + } else { + return _zeroProj(); + } } - } - a = U384.modmul(call, z0, z1, p); + a = U384.modmul(call, z0, z1, p); - return _addProj2(call, p, a, z2, y1, y2, x2); + return _addProj2(call, p, a, z2, y1, y2, x2); + } } /** @@ -319,41 +315,43 @@ contract PECDSASHA1U384Authenticator { uint256 t1, uint256 t0 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { - u0 = u0.copy(); - u1 = u1.copy(); - t0 = t0.copy(); + unchecked { + u0 = u0.copy(); + u1 = u1.copy(); + t0 = t0.copy(); - uint256 diff = U384.sub(p, t1); - y2 = U384.modadd(call, t0, diff, p); + uint256 diff = U384.sub(p, t1); + y2 = U384.modadd(call, t0, diff, p); - U384.subAssignTo(diff, p, u1); - x2 = U384.modadd(call, u0, diff, p); - uint256 u2 = U384.modexp(call, x2, 2, p); + U384.subAssignTo(diff, p, u1); + x2 = U384.modadd(call, u0, diff, p); + uint256 u2 = U384.modexp(call, x2, 2, p); - z2 = U384.modexp(call, y2, 2, p); + z2 = U384.modexp(call, y2, 2, p); - U384.modmulAssign(call, z2, v, p); - U384.modaddAssign(call, u1, u0, p); - U384.modmulAssign(call, u1, u2, p); - U384.subAssignTo(diff, p, u1); - U384.modaddAssign(call, z2, diff, p); + U384.modmulAssign(call, z2, v, p); + U384.modaddAssign(call, u1, u0, p); + U384.modmulAssign(call, u1, u2, p); + U384.subAssignTo(diff, p, u1); + U384.modaddAssign(call, z2, diff, p); - uint256 u3 = U384.modmul(call, u2, x2, p); + uint256 u3 = U384.modmul(call, u2, x2, p); - U384.modmulAssign(call, x2, z2, p); + U384.modmulAssign(call, x2, z2, p); - U384.modmulAssign(call, u0, u2, p); + U384.modmulAssign(call, u0, u2, p); - U384.subAssignTo(diff, p, z2); - U384.modaddAssign(call, u0, diff, p); - U384.modmulAssign(call, y2, u0, p); - U384.modmulAssign(call, t0, u3, p); + U384.subAssignTo(diff, p, z2); + U384.modaddAssign(call, u0, diff, p); + U384.modmulAssign(call, y2, u0, p); + U384.modmulAssign(call, t0, u3, p); - U384.subAssignTo(diff, p, t0); - U384.modaddAssign(call, y2, diff, p); + U384.subAssignTo(diff, p, t0); + U384.modaddAssign(call, y2, diff, p); - U384.modmulAssign(call, u3, v, p); // stack too deep - z2 = u3; + U384.modmulAssign(call, u3, v, p); // stack too deep + z2 = u3; + } } /** @@ -369,11 +367,13 @@ contract PECDSASHA1U384Authenticator { uint256 x1, uint256 y1 ) internal view returns (uint256, uint256) { - uint256 z0; + unchecked { + uint256 z0; - (x0, y0, z0) = _addProj(call, p, three, a, x0, y0, U384.init(1), x1, y1, U384.init(1)); + (x0, y0, z0) = _addProj(call, p, three, a, x0, y0, U384.init(1), x1, y1, U384.init(1)); - return _toAffinePoint(call, p, x0, y0, z0); + return _toAffinePoint(call, p, x0, y0, z0); + } } /** @@ -387,11 +387,13 @@ contract PECDSASHA1U384Authenticator { uint256 x0, uint256 y0 ) internal view returns (uint256, uint256) { - uint256 z0; + unchecked { + uint256 z0; - (x0, y0, z0) = _twiceProj(call, p, three, a, x0, y0, U384.init(1)); + (x0, y0, z0) = _twiceProj(call, p, three, a, x0, y0, U384.init(1)); - return _toAffinePoint(call, p, x0, y0, z0); + return _toAffinePoint(call, p, x0, y0, z0); + } } /** @@ -407,11 +409,13 @@ contract PECDSASHA1U384Authenticator { uint256 x2, uint256 y2 ) internal view returns (uint256[3] memory P) { - uint256 x; - uint256 y; + unchecked { + uint256 x; + uint256 y; - (x, y) = _add(call, p, three, a, x1, y1, x2, y2); - return _toProjectivePoint(call, p, x, y); + (x, y) = _add(call, p, three, a, x1, y1, x2, y2); + return _toProjectivePoint(call, p, x, y); + } } /** @@ -424,8 +428,10 @@ contract PECDSASHA1U384Authenticator { uint256 y0, uint256 z0 ) internal view returns (uint256 x1, uint256 y1) { - x1 = U384.moddiv(call, x0, z0, p); - y1 = U384.moddiv(call, y0, z0, p); + unchecked { + x1 = U384.moddiv(call, x0, z0, p); + y1 = U384.moddiv(call, y0, z0, p); + } } /** @@ -439,22 +445,24 @@ contract PECDSASHA1U384Authenticator { uint256 x, uint256 y ) internal view returns (bool) { - if (U384.eqInteger(x, 0) || U384.eq(x, p) || U384.eqInteger(y, 0) || U384.eq(y, p)) { - return false; - } + unchecked { + if (U384.eqInteger(x, 0) || U384.eq(x, p) || U384.eqInteger(y, 0) || U384.eq(y, p)) { + return false; + } - uint256 LHS = U384.modexp(call, y, 2, p); - uint256 RHS = U384.modexp(call, x, 3, p); + uint256 LHS = U384.modexp(call, y, 2, p); + uint256 RHS = U384.modexp(call, x, 3, p); - if (!U384.eqInteger(a, 0)) { - RHS = U384.modadd(call, RHS, U384.modmul(call, x, a, p), p); // x^3 + a*x - } + if (!U384.eqInteger(a, 0)) { + RHS = U384.modadd(call, RHS, U384.modmul(call, x, a, p), p); // x^3 + a*x + } - if (!U384.eqInteger(b, 0)) { - RHS = U384.modadd(call, RHS, b, p); // x^3 + a*x + b - } + if (!U384.eqInteger(b, 0)) { + RHS = U384.modadd(call, RHS, b, p); // x^3 + a*x + b + } - return U384.eq(LHS, RHS); + return U384.eq(LHS, RHS); + } } /** @@ -466,9 +474,11 @@ contract PECDSASHA1U384Authenticator { uint256 x0, uint256 y0 ) internal view returns (uint256[3] memory P) { - P[2] = U384.init(1); - P[0] = U384.modmul(call, x0, P[2], p); - P[1] = U384.modmul(call, y0, P[2], p); + unchecked { + P[2] = U384.init(1); + P[0] = U384.modmul(call, x0, P[2], p); + P[1] = U384.modmul(call, y0, P[2], p); + } } /** diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index e580ea3..52d4693 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -7,26 +7,30 @@ library U384 { uint256 private constant CALL_ALLOCATION = 288; function init(uint256 from_) internal pure returns (uint256 handler_) { - handler_ = _allocate(SHORT_ALLOCATION); + unchecked { + handler_ = _allocate(SHORT_ALLOCATION); - assembly { - mstore(handler_, 0x00) - mstore(add(0x20, handler_), from_) - } + assembly { + mstore(handler_, 0x00) + mstore(add(0x20, handler_), from_) + } - return handler_; + return handler_; + } } function init(bytes memory from_) internal pure returns (uint256 handler_) { - handler_ = _allocate(SHORT_ALLOCATION); + unchecked { + handler_ = _allocate(SHORT_ALLOCATION); - assembly { - mstore(handler_, 0x00) - mstore(add(handler_, 0x10), mload(add(from_, 0x20))) - mstore(add(handler_, 0x20), mload(add(from_, 0x30))) - } + assembly { + mstore(handler_, 0x00) + mstore(add(handler_, 0x10), mload(add(from_, 0x20))) + mstore(add(handler_, 0x20), mload(add(from_, 0x30))) + } - return handler_; + return handler_; + } } function assign(uint256 to_, uint256 from_) internal pure { @@ -44,18 +48,22 @@ library U384 { } function initCall() internal pure returns (uint256 handler_) { - return _allocate(CALL_ALLOCATION); + unchecked { + return _allocate(CALL_ALLOCATION); + } } function copy(uint256 handler_) internal pure returns (uint256 handlerCopy_) { - handlerCopy_ = _allocate(SHORT_ALLOCATION); + unchecked { + handlerCopy_ = _allocate(SHORT_ALLOCATION); - assembly { - mstore(handlerCopy_, mload(handler_)) - mstore(add(handlerCopy_, 0x20), mload(add(handler_, 0x20))) - } + assembly { + mstore(handlerCopy_, mload(handler_)) + mstore(add(handlerCopy_, 0x20), mload(add(handler_, 0x20))) + } - return handlerCopy_; + return handlerCopy_; + } } function eq(uint256 a_, uint256 b_) internal pure returns (bool eq_) { @@ -71,81 +79,88 @@ library U384 { } function cmp(uint256 a_, uint256 b_) internal pure returns (int256 cmp_) { - uint256 aWord_; - uint256 bWord_; + unchecked { + uint256 aWord_; + uint256 bWord_; - assembly { - aWord_ := mload(a_) - bWord_ := mload(b_) - } + assembly { + aWord_ := mload(a_) + bWord_ := mload(b_) + } - if (aWord_ > bWord_) { - return 1; - } + if (aWord_ > bWord_) { + return 1; + } - if (aWord_ < bWord_) { - return -1; - } + if (aWord_ < bWord_) { + return -1; + } - assembly { - aWord_ := mload(add(a_, 0x20)) - bWord_ := mload(add(b_, 0x20)) - } + assembly { + aWord_ := mload(add(a_, 0x20)) + bWord_ := mload(add(b_, 0x20)) + } - if (aWord_ > bWord_) { - return 1; - } + if (aWord_ > bWord_) { + return 1; + } - if (aWord_ < bWord_) { - return -1; + if (aWord_ < bWord_) { + return -1; + } } - - return 0; } function cmpInteger(uint256 a_, uint256 bInteger_) internal pure returns (int256 cmp_) { - uint256 aWord_; + unchecked { + uint256 aWord_; - assembly { - aWord_ := mload(a_) - } + assembly { + aWord_ := mload(a_) + } - if (aWord_ > 0) { - return 1; - } + if (aWord_ > 0) { + return 1; + } - assembly { - aWord_ := mload(add(a_, 0x20)) - } + assembly { + aWord_ := mload(add(a_, 0x20)) + } - if (aWord_ > bInteger_) { - return 1; - } + if (aWord_ > bInteger_) { + return 1; + } - if (aWord_ < bInteger_) { - return -1; + if (aWord_ < bInteger_) { + return -1; + } } - - return 0; } - function modexp(uint256 call_, uint256 b_, uint256 eInteger_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + function modexp( + uint256 call_, + uint256 b_, + uint256 eInteger_, + uint256 m_ + ) internal view returns (uint256 r_) { + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0x60, call_), mload(b_)) - mstore(add(0x80, call_), mload(add(b_, 0x20))) - mstore(add(0xA0, call_), eInteger_) - mstore(add(0xC0, call_), mload(m_)) - mstore(add(0xE0, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0x60, call_), mload(b_)) + mstore(add(0x80, call_), mload(add(b_, 0x20))) + mstore(add(0xA0, call_), eInteger_) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) - } + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) + } - return r_; + return r_; + } } function modexpAssign(uint256 call_, uint256 b_, uint256 eInteger_, uint256 m_) internal view { @@ -163,7 +178,13 @@ library U384 { } } - function modexpAssignTo(uint256 call_, uint256 to_, uint256 b_, uint256 eInteger_, uint256 m_) internal view { + function modexpAssignTo( + uint256 call_, + uint256 to_, + uint256 b_, + uint256 eInteger_, + uint256 m_ + ) internal view { assembly { mstore(call_, 0x40) mstore(add(0x20, call_), 0x20) @@ -178,249 +199,315 @@ library U384 { } } - function modadd(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + function modadd( + uint256 call_, + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view returns (uint256 r_) { + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - _add(a_, b_, call_ + 0x60); + _add(a_, b_, call_ + 0x60); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xA0, call_), 0x01) - mstore(add(0xC0, call_), mload(m_)) - mstore(add(0xE0, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) - } + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) + } - return r_; + return r_; + } } function modaddAssign(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view { - _add(a_, b_, call_ + 0x60); + unchecked { + _add(a_, b_, call_ + 0x60); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xA0, call_), 0x01) - mstore(add(0xC0, call_), mload(m_)) - mstore(add(0xE0, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0100, a_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0100, a_, 0x40)) + } } } - function modaddAssignTo(uint256 call_, uint256 to_, uint256 a_, uint256 b_, uint256 m_) internal view { - _add(a_, b_, call_ + 0x60); + function modaddAssignTo( + uint256 call_, + uint256 to_, + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view { + unchecked { + _add(a_, b_, call_ + 0x60); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xA0, call_), 0x01) - mstore(add(0xC0, call_), mload(m_)) - mstore(add(0xE0, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) + } } } function mod(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { - r_ = modexp(call_, a_, 1, m_); + unchecked { + r_ = modexp(call_, a_, 1, m_); - return r_; + return r_; + } } - function modsub(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + function modsub( + uint256 call_, + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view returns (uint256 r_) { + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - _sub(a_, b_, call_ + 0x60); + _sub(a_, b_, call_ + 0x60); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xA0, call_), 0x01) - mstore(add(0xC0, call_), mload(m_)) - mstore(add(0xE0, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) - } + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) + } - return r_; + return r_; + } } - function modmul(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + function modmul( + uint256 call_, + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view returns (uint256 r_) { + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - _mul(a_, b_, call_ + 0x60); + _mul(a_, b_, call_ + 0x60); - assembly { - mstore(call_, 0x60) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xC0, call_), 0x01) - mstore(add(0xE0, call_), mload(m_)) - mstore(add(0x0100, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x60) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xC0, call_), 0x01) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) - } + pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) + } - return r_; + return r_; + } } function modmulAssign(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view { - _mul(a_, b_, call_ + 0x60); + unchecked { + _mul(a_, b_, call_ + 0x60); - assembly { - mstore(call_, 0x60) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xC0, call_), 0x01) - mstore(add(0xE0, call_), mload(m_)) - mstore(add(0x0100, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x60) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xC0, call_), 0x01) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0120, a_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0120, a_, 0x40)) + } } } - function modmulAssignTo(uint256 call_, uint256 to_, uint256 a_, uint256 b_, uint256 m_) internal view { - _mul(a_, b_, call_ + 0x60); + function modmulAssignTo( + uint256 call_, + uint256 to_, + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view { + unchecked { + _mul(a_, b_, call_ + 0x60); - assembly { - mstore(call_, 0x60) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xC0, call_), 0x01) - mstore(add(0xE0, call_), mload(m_)) - mstore(add(0x0100, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x60) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xC0, call_), 0x01) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0120, to_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0120, to_, 0x40)) + } } } function modinv(uint256 call_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - _sub(m_, init(2), call_ + 0xA0); + _sub(m_, init(2), call_ + 0xA0); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x40) - mstore(add(0x40, call_), 0x40) - mstore(add(0x60, call_), mload(b_)) - mstore(add(0x80, call_), mload(add(b_, 0x20))) - mstore(add(0xE0, call_), mload(m_)) - mstore(add(0x0100, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x40) + mstore(add(0x40, call_), 0x40) + mstore(add(0x60, call_), mload(b_)) + mstore(add(0x80, call_), mload(add(b_, 0x20))) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) + } } } - function moddiv(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + function moddiv( + uint256 call_, + uint256 a_, + uint256 b_, + uint256 m_ + ) internal view returns (uint256 r_) { + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - _sub(m_, init(2), call_ + 0xA0); + _sub(m_, init(2), call_ + 0xA0); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x40) - mstore(add(0x40, call_), 0x40) - mstore(add(0x60, call_), mload(b_)) - mstore(add(0x80, call_), mload(add(b_, 0x20))) - mstore(add(0xE0, call_), mload(m_)) - mstore(add(0x0100, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x40) + mstore(add(0x40, call_), 0x40) + mstore(add(0x60, call_), mload(b_)) + mstore(add(0x80, call_), mload(add(b_, 0x20))) + mstore(add(0xE0, call_), mload(m_)) + mstore(add(0x0100, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) - } + pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) + } - return modmul(call_, a_, r_, m_); + return modmul(call_, a_, r_, m_); + } } function add(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - _add(a_, b_, r_); + _add(a_, b_, r_); - return r_; + return r_; + } } function sub(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - _sub(a_, b_, r_); + _sub(a_, b_, r_); - return r_; + return r_; + } } - function subAssignTo(uint256 to_, uint256 a_, uint256 b_) internal pure returns (uint256 r_) { - _sub(a_, b_, to_); + function subAssignTo(uint256 to_, uint256 a_, uint256 b_) internal pure { + unchecked { + _sub(a_, b_, to_); + } } function toBytes(uint256 handler_) internal pure returns (bytes memory bytes_) { - uint256 bytesHandler_ = _allocate(LONG_ALLOCATION); + unchecked { + uint256 bytesHandler_ = _allocate(LONG_ALLOCATION); - assembly { - bytes_ := bytesHandler_ + assembly { + bytes_ := bytesHandler_ - mstore(bytes_, 0x40) - mstore(add(0x20, bytes_), mload(handler_)) - mstore(add(0x40, bytes_), mload(add(handler_, 0x20))) - } + mstore(bytes_, 0x40) + mstore(add(0x20, bytes_), mload(handler_)) + mstore(add(0x40, bytes_), mload(add(handler_, 0x20))) + } - return bytes_; + return bytes_; + } } function modshl1(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { - r_ = _allocate(SHORT_ALLOCATION); + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - _shl1(a_, m_, call_ + 0x60); + _shl1(a_, call_ + 0x60); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xA0, call_), 0x01) - mstore(add(0xC0, call_), mload(m_)) - mstore(add(0xE0, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) + } } } function modshl1Assign(uint256 call_, uint256 a_, uint256 m_) internal view { - _shl1(a_, m_, call_ + 0x60); + unchecked { + _shl1(a_, call_ + 0x60); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xA0, call_), 0x01) - mstore(add(0xC0, call_), mload(m_)) - mstore(add(0xE0, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0100, a_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0100, a_, 0x40)) + } } } function modshl1AssignTo(uint256 call_, uint256 to_, uint256 a_, uint256 m_) internal view { - _shl1(a_, m_, call_ + 0x60); + unchecked { + _shl1(a_, call_ + 0x60); - assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) - mstore(add(0xA0, call_), 0x01) - mstore(add(0xC0, call_), mload(m_)) - mstore(add(0xE0, call_), mload(add(m_, 0x20))) + assembly { + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) + } } } - function _shl1(uint256 a_, uint256 m_, uint256 r_) internal view { + function _shl1(uint256 a_, uint256 r_) internal pure { assembly { let a0_ := mload(a_) let a1_ := mload(add(a_, 0x20)) @@ -487,7 +574,7 @@ library U384 { // r3 current_ := add(shl(128, curry_), shr(128, current_)) - curry_ := callvalue() // equals := 0 but less expensive + curry_ := callvalue() // same as := 0 but less expensive temp_ := mul(a0_, b2_) current_ := add(current_, temp_) @@ -519,22 +606,20 @@ library U384 { // r1 current_ := add(shl(128, curry_), shr(128, current_)) - curry_ := callvalue() - - temp_ := mul(a0_, b0_) - current_ := add(current_, temp_) - curry_ := lt(current_, temp_) + current_ := add(current_, mul(a0_, b0_)) mstore(r_, current_) } } function _allocate(uint256 bytes_) private pure returns (uint256 handler_) { - assembly { - handler_ := mload(0x40) - mstore(0x40, add(handler_, bytes_)) - } + unchecked { + assembly { + handler_ := mload(0x40) + mstore(0x40, add(handler_, bytes_)) + } - return handler_; + return handler_; + } } } From 201bd0ac06a11c0761f60594b1deccc34b8b6a34 Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Mon, 21 Oct 2024 19:03:35 +0300 Subject: [PATCH 31/45] small --- .../PECDSASHA1U384Authenticator.sol | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index cce0330..08ce852 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -161,8 +161,7 @@ contract PECDSASHA1U384Authenticator { y1 = U384.copy(y0); } - lowBits_ >>= 1; - lowBits_ |= highBits_ << 255; + lowBits_ = (lowBits_ >> 1) | (highBits_ << 255); highBits_ >>= 1; while (lowBits_ > 0 || highBits_ > 0) { @@ -191,8 +190,7 @@ contract PECDSASHA1U384Authenticator { ); } - lowBits_ >>= 1; - lowBits_ |= highBits_ << 255; + lowBits_ = (lowBits_ >> 1) | (highBits_ << 255); highBits_ >>= 1; } @@ -214,14 +212,14 @@ contract PECDSASHA1U384Authenticator { uint256 z0 ) internal view returns (uint256 x1, uint256 y1, uint256 z1) { unchecked { - x0 = x0.copy(); - y0 = y0.copy(); - z0 = z0.copy(); - if (_isZeroCurve(x0, y0)) { return _zeroProj(); } + x0 = x0.copy(); + y0 = y0.copy(); + z0 = z0.copy(); + uint256 u = U384.modmul(call, y0, z0, p); U384.modshl1Assign(call, u, p); @@ -299,7 +297,7 @@ contract PECDSASHA1U384Authenticator { a = U384.modmul(call, z0, z1, p); - return _addProj2(call, p, a, z2, y1, y2, x2); + return _addProj2(call, a, z2, p, y1, y2, x2); } } @@ -308,9 +306,9 @@ contract PECDSASHA1U384Authenticator { */ function _addProj2( uint256 call, - uint256 p, uint256 v, uint256 u0, + uint256 p, uint256 u1, uint256 t1, uint256 t0 @@ -349,8 +347,7 @@ contract PECDSASHA1U384Authenticator { U384.subAssignTo(diff, p, t0); U384.modaddAssign(call, y2, diff, p); - U384.modmulAssign(call, u3, v, p); // stack too deep - z2 = u3; + U384.modmulAssignTo(call, z2, u3, v, p); } } @@ -429,8 +426,7 @@ contract PECDSASHA1U384Authenticator { uint256 z0 ) internal view returns (uint256 x1, uint256 y1) { unchecked { - x1 = U384.moddiv(call, x0, z0, p); - y1 = U384.moddiv(call, y0, z0, p); + return (U384.moddiv(call, x0, z0, p), U384.moddiv(call, y0, z0, p)); } } @@ -485,20 +481,26 @@ contract PECDSASHA1U384Authenticator { * @dev Return the zero curve in projective coordinates. */ function _zeroProj() internal pure returns (uint256 x, uint256 y, uint256 z) { - return (U384.init(0), U384.init(1), U384.init(0)); + unchecked { + return (U384.init(0), U384.init(1), U384.init(0)); + } } /** * @dev Return the zero curve in affine coordinates. */ function _zeroAffine() internal pure returns (uint256 x, uint256 y) { - return (U384.init(0), U384.init(0)); + unchecked { + return (U384.init(0), U384.init(0)); + } } /** * @dev Check if the curve is the zero curve. */ function _isZeroCurve(uint256 x0, uint256 y0) internal pure returns (bool isZero) { - return U384.eqInteger(x0, 0) && U384.eqInteger(y0, 0); + unchecked { + return U384.eqInteger(x0, 0) && U384.eqInteger(y0, 0); + } } } From dd8cf9f608cf448cca4519fcb5087ec27b95df7c Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Tue, 22 Oct 2024 00:27:01 +0300 Subject: [PATCH 32/45] 21.38kk --- .../PECDSASHA1U384Authenticator.sol | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol index 08ce852..bd2b53f 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol @@ -216,10 +216,6 @@ contract PECDSASHA1U384Authenticator { return _zeroProj(); } - x0 = x0.copy(); - y0 = y0.copy(); - z0 = z0.copy(); - uint256 u = U384.modmul(call, y0, z0, p); U384.modshl1Assign(call, u, p); @@ -227,11 +223,11 @@ contract PECDSASHA1U384Authenticator { U384.modmulAssign(call, x1, y0, p); U384.modshl1Assign(call, x1, p); - U384.modexpAssign(call, x0, 2, p); + x0 = U384.modexp(call, x0, 2, p); y1 = U384.modmul(call, x0, three, p); - U384.modexpAssign(call, z0, 2, p); + z0 = U384.modexp(call, z0, 2, p); U384.modmulAssign(call, z0, a, p); U384.modaddAssign(call, y1, z0, p); @@ -245,7 +241,7 @@ contract PECDSASHA1U384Authenticator { U384.modaddAssignTo(call, x0, x1, diff, p); U384.modmulAssign(call, x0, y1, p); - U384.modmulAssign(call, y0, u, p); + y0 = U384.modmul(call, y0, u, p); U384.modexpAssign(call, y0, 2, p); U384.modshl1Assign(call, y0, p); @@ -314,10 +310,6 @@ contract PECDSASHA1U384Authenticator { uint256 t0 ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { unchecked { - u0 = u0.copy(); - u1 = u1.copy(); - t0 = t0.copy(); - uint256 diff = U384.sub(p, t1); y2 = U384.modadd(call, t0, diff, p); @@ -328,7 +320,7 @@ contract PECDSASHA1U384Authenticator { z2 = U384.modexp(call, y2, 2, p); U384.modmulAssign(call, z2, v, p); - U384.modaddAssign(call, u1, u0, p); + u1 = U384.modadd(call, u1, u0, p); U384.modmulAssign(call, u1, u2, p); U384.subAssignTo(diff, p, u1); U384.modaddAssign(call, z2, diff, p); @@ -337,12 +329,12 @@ contract PECDSASHA1U384Authenticator { U384.modmulAssign(call, x2, z2, p); - U384.modmulAssign(call, u0, u2, p); + u0 = U384.modmul(call, u0, u2, p); U384.subAssignTo(diff, p, z2); U384.modaddAssign(call, u0, diff, p); U384.modmulAssign(call, y2, u0, p); - U384.modmulAssign(call, t0, u3, p); + t0 = U384.modmul(call, t0, u3, p); U384.subAssignTo(diff, p, t0); U384.modaddAssign(call, y2, diff, p); From fadd67af85369c9d4d3d2ec372e96782a027232f Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Thu, 24 Oct 2024 19:41:11 +0300 Subject: [PATCH 33/45] cleaned up repo --- ...tor.sol => PECDSA384SHA2Authenticator.sol} | 17 +- .../PECDSASHA1Authenticator.sol | 32 +- .../PECDSASHA2Authenticator.sol | 335 ----- .../PECDSASHA2NewAuthenticator.sol | 600 -------- contracts/utils/BigInt.sol | 1309 ----------------- contracts/utils/BigIntOpt.sol | 1200 --------------- contracts/utils/BigNumbers.sol | 1309 ----------------- contracts/utils/MemoryStack.sol | 124 -- contracts/utils/MemoryUint.sol | 764 ---------- .../PECDSA384SHA2Authenticator.test.ts | 35 + .../PECDSAAuthenticator.test.ts | 118 -- .../PECDSASHA1Authenticator.test.ts | 6 +- test/utils/Stack.test.ts | 30 - 13 files changed, 58 insertions(+), 5821 deletions(-) rename contracts/passport/authenticators/{PECDSASHA1U384Authenticator.sol => PECDSA384SHA2Authenticator.sol} (97%) delete mode 100644 contracts/passport/authenticators/PECDSASHA2Authenticator.sol delete mode 100644 contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol delete mode 100644 contracts/utils/BigInt.sol delete mode 100644 contracts/utils/BigIntOpt.sol delete mode 100644 contracts/utils/BigNumbers.sol delete mode 100644 contracts/utils/MemoryStack.sol delete mode 100644 contracts/utils/MemoryUint.sol create mode 100644 test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts delete mode 100644 test/passport/authenticators/PECDSAAuthenticator.test.ts delete mode 100644 test/utils/Stack.test.ts diff --git a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol b/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol similarity index 97% rename from contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol rename to contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol index bd2b53f..ba1b468 100644 --- a/contracts/passport/authenticators/PECDSASHA1U384Authenticator.sol +++ b/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol @@ -6,7 +6,7 @@ import {U384} from "../../utils/U384.sol"; /** * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol */ -contract PECDSASHA1U384Authenticator { +contract PECDSA384SHA2Authenticator { using U384 for *; struct Parameters { @@ -44,11 +44,6 @@ contract PECDSASHA1U384Authenticator { Inputs memory inputs ) external view returns (bool) { unchecked { - /// @dev accept s only from the lower part of the curve - // if (r == 0 || r >= n || s == 0 || s > lowSmax) { - // return false; - // } - _Inputs memory _inputs; _inputs.r = U384.init(inputs.r); @@ -76,6 +71,16 @@ contract PECDSASHA1U384Authenticator { three: U384.init(3) }); + /// @dev accept s only from the lower part of the curve +// if ( +// U384.eqInteger(_inputs.r, 0) || +// U384.cmp(_inputs.r, params.n) != -1 || +// U384.eqInteger(_inputs.s, 0) || +// U384.cmp(_inputs.s, params.lowSmax) == 1 +// ) { +// return false; +// } + if (!_isOnCurve(params.call, params.p, params.a, params.b, _inputs.x, _inputs.y)) { return false; } diff --git a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol index 9e29380..1d65d1d 100644 --- a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.16; import {SHA1} from "../../utils/SHA1.sol"; -import "hardhat/console.sol"; /** * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol @@ -32,9 +31,9 @@ contract PECDSASHA1Authenticator { uint256 y ) external pure returns (bool) { /// @dev accept s only from the lower part of the curve - // if (r == 0 || r >= n || s == 0 || s > lowSmax) { - // return false; - // } +// if (r == 0 || r >= n || s == 0 || s > lowSmax) { +// return false; +// } if (!_isOnCurve(x, y)) { return false; @@ -50,31 +49,18 @@ contract PECDSASHA1Authenticator { uint256 sInv = _inverseMod(s, n); (x1, y1) = _multiplyScalar(gx, gy, mulmod(message, sInv, n)); - console.log("x1y1"); - console.logBytes32(bytes32(x1)); - console.logBytes32(bytes32(y1)); - (x2, y2) = _multiplyScalar(x, y, mulmod(r, sInv, n)); - console.log("x2y2"); - console.logBytes32(bytes32(x2)); - console.logBytes32(bytes32(y2)); uint256[3] memory P = _addAndReturnProjectivePoint(x1, y1, x2, y2); - console.logBytes32(bytes32(P[0])); - console.logBytes32(bytes32(P[1])); - console.logBytes32(bytes32(P[2])); - - // if (P[2] == 0) { - // return false; - // } - - // uint256 Px = _inverseMod(P[2], p); - // Px = mulmod(P[0], mulmod(Px, Px, p), p); + if (P[2] == 0) { + return false; + } - // return Px % n == r; + uint256 Px = _inverseMod(P[2], p); + Px = mulmod(P[0], mulmod(Px, Px, p), p); - return true; + return Px % n == r; } /** diff --git a/contracts/passport/authenticators/PECDSASHA2Authenticator.sol b/contracts/passport/authenticators/PECDSASHA2Authenticator.sol deleted file mode 100644 index 5da599d..0000000 --- a/contracts/passport/authenticators/PECDSASHA2Authenticator.sol +++ /dev/null @@ -1,335 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.17; - -import "hardhat/console.sol"; -import "../../utils/BigInt.sol"; -import "../../utils/BigIntOpt.sol"; - -/** - * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol - */ -contract PECDSASHA2Authenticator { - using BigInts for *; - using BigIntsOpt for *; - - BigInt zero = BigInts.zero(); - BigInt one = BigInts.one(); - BigInt two = BigInts.two(); - - BigIntOpt zeroOpt = BigIntsOpt.zero(); - BigIntOpt oneOpt = BigIntsOpt.one(); - BigIntOpt twoOpt = BigIntsOpt.two(); - - // Set parameters for curve. - secp384r1 - BigInt a = hex"7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9".init(false); - BigInt b = hex"26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6".init(false); - BigInt gx = - hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" - .init(false); - BigInt gy = - hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" - .init(false); - BigInt p = hex"A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377".init(false); - BigInt n = - hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" - .init(false); - - BigInt lowSmax = - hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" - .init(false); - - BigIntOpt aOpt = - hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" - .initOpt(false); - BigIntOpt bOpt = - hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF" - .initOpt(false); - BigIntOpt gxOpt = - hex"aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7" - .initOpt(false); - BigIntOpt gyOpt = - hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" - .initOpt(false); - BigIntOpt pOpt = - hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" - .initOpt(false); - BigIntOpt nOpt = - hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" - .initOpt(false); - - BigIntOpt lowSmaxOpt = - hex"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b" - .initOpt(false); - - // step1 - function authenticate( - bytes memory challange, - bytes memory r, - bytes memory s, - bytes memory x, - bytes memory y - ) - external - view - returns ( - // bytes memory x0, - // bytes memory Px - bool - ) - { - BigInt memory r_ = r.init(false); - - //require(!r_.isZero() && !r_.gte(n) && !s.init(false).isZero()); // && !s.init(false).gt(lowSmax)); - require(_isOnCurve(x.init(false), y.init(false)), "Sec384: Not on curve"); - - // BigInt memory Px_ = Px.init(false); - // BigInt memory P = _toProjectivePoint(x0.init(false)); - - // Px_ = BigInts.modmul(P, BigInts.modmul(Px_, Px_, p), p); - - // return Px_.mod(n).eq(r_); - - return true; - } - - /** - * @dev Check if a point in affine coordinates is on the curve. - */ - function _isOnCurve(BigInt memory x, BigInt memory y) internal view returns (bool) { - if (x.isZero() || x.eq(p) || y.isZero() || y.eq(p)) { - return false; - } - - BigInt memory LHS = BigInts.modmul(y, y, p); // y^2 - BigInt memory RHS = BigInts.modmul(BigInts.modmul(x, x, p), x, p); // x^3 - - if (!a.isZero()) { - RHS = RHS.add(BigInts.modmul(x, a, p)).mod(p); - } - - if (!b.isZero()) { - RHS = RHS.add(b).mod(p); // x^3 + a*x + b - } - - return LHS.eq(RHS); - } - - /** - * @dev Transform affine coordinates into projective coordinates. - */ - function _toProjectivePoint(BigInt memory x0) internal view returns (BigInt memory) { - BigInt memory P = zero.add(one).mod(p); // P[2] - - require(!P.isZero()); - - return BigInts.modmul(x0, P, p); // P[0] - //P[1] = BigInts.modmul(y0, P[2], p); - } - - function _multiplyScalarPartial( - bytes memory x0, - bytes memory y0, - bytes memory scalar - ) public view returns (BigInt memory x1, BigInt memory y1, BigInt memory z1) { - BigInt memory x0_ = x0.init(false); - BigInt memory y0_ = y0.init(false); - BigInt memory scalar_ = scalar.init(false); - - // if (scalar === 0n) { - // return zeroAffine(); - // } else if (scalar === 1n) { - // return { x: x0, y: y0 }; - // } else if (scalar === 2n) { - // return twice(x0, y0); - // } - - BigInt memory base2X = x0_; - BigInt memory base2Y = y0_; - BigInt memory base2Z = one; - z1 = one; - x1 = x0_; - y1 = y0_; - - if (scalar_.mod(two).eq(one)) { - x1 = zero; - y1 = zero; - } - - scalar_ = scalar_.shr(1); - - //uint i = 0; - //while (scalar_.gt(zero)) { - // 382 - for (uint i = 0; i < 5; i++) { - (base2X, base2Y, base2Z) = _twiceProj(base2X, base2Y, base2Z); - - if (scalar_.mod(two).eq(one)) { - (x1, y1, z1) = _addProj(base2X, base2Y, base2Z, x1, y1, z1); - } - - scalar_ = scalar_.shr(1); - } - - // console.logBytes(base2X.val); - // console.logBytes(base2Y.val); - // console.logBytes(base2Z.val); - console.logBytes(x1.val); - console.logBytes(y1.val); - console.logBytes(z1.val); - - bytes32 size; - - console.log("msize"); - //4.211.872 - //4044a0 - assembly { - size := msize() - } - - console.log(uint256(size)); - - console.log("================"); - } - - function _twiceProj( - BigInt memory x0, - BigInt memory y0, - BigInt memory z0 - ) internal view returns (BigInt memory x1, BigInt memory y1, BigInt memory z1) { - BigInt memory t; - BigInt memory u; - BigInt memory v; - BigInt memory w; - - // if (_isZeroCurve(x0, y0)) { - // return _zeroProj(); - // } - - u = BigInts.modmul(y0, z0, p); - u = BigInts.modmul(u, two, p); - - v = BigInts.modmul(u, x0, p); - v = BigInts.modmul(v, y0, p); - v = BigInts.modmul(v, two, p); - - x0 = BigInts.modmul(x0, x0, p); - t = BigInts.modmul(x0, 3.init(false), p); - - z0 = BigInts.modmul(z0, z0, p); - z0 = BigInts.modmul(z0, a, p); - - // //t = (t + z0) % p; - t = t.add(z0).mod(p); - - w = BigInts.modmul(t, t, p); - x0 = BigInts.modmul(two, v, p); - - // //w = (w + (p - x0)) % p; - w = w.add(p.sub(x0)).mod(p); - - // //x0 = (v + (p - w)) % p; - x0 = v.add(p.sub(w)).mod(p); - - x0 = BigInts.modmul(t, x0, p); - y0 = BigInts.modmul(y0, u, p); - y0 = BigInts.modmul(y0, y0, p); - y0 = BigInts.modmul(two, y0, p); - - // //y1 = (x0 + (p - y0)) % p; - y1 = x0.add(p.sub(y0)).mod(p); - - x1 = BigInts.modmul(u, w, p); - - z1 = BigInts.modmul(u, u, p); - z1 = BigInts.modmul(z1, u, p); - } - - //2,724,209 - function _addProj( - BigInt memory x0, - BigInt memory y0, - BigInt memory z0, - BigInt memory x1, - BigInt memory y1, - BigInt memory z1 - ) internal view returns (BigInt memory x2, BigInt memory y2, BigInt memory z2) { - BigInt memory t0; - BigInt memory t1; - BigInt memory u0; - BigInt memory u1; - - if (_isZeroCurve(x0, y0)) { - return (x1, y1, z1); - } else if (_isZeroCurve(x1, y1)) { - return (x0, y0, z0); - } - - t0 = BigInts.modmul(y0, z1, p); - t1 = BigInts.modmul(y1, z0, p); - - u0 = BigInts.modmul(x0, z1, p); - u1 = BigInts.modmul(x1, z0, p); - - if (u0.eq(u1)) { - if (t0.eq(t1)) { - return _twiceProj(x0, y0, z0); - } else { - return _zeroProj(); - } - } - - (x2, y2, z2) = _addProj2(BigInts.modmul(z0, z1, p), u0, u1, t1, t0); - } - - /** - * @dev Helper function that splits addProj to avoid too many local variables. - */ - function _addProj2( - BigInt memory v, - BigInt memory u0, - BigInt memory u1, - BigInt memory t1, - BigInt memory t0 - ) internal view returns (BigInt memory x2, BigInt memory y2, BigInt memory z2) { - BigInt memory u; - BigInt memory u2; - BigInt memory u3; - BigInt memory w; - BigInt memory t; - - t = t0.add(p.sub(t1)).mod(p); - u = u0.add(p.sub(u1)).mod(p); - u2 = BigInts.modmul(u, u, p); - - w = BigInts.modmul(t, t, p); - w = BigInts.modmul(w, v, p); - u1 = u1.add(u0).mod(p); - u1 = BigInts.modmul(u1, u2, p); - w = w.add(p.sub(u1)).mod(p); - - x2 = BigInts.modmul(u, w, p); - - u3 = BigInts.modmul(u2, u, p); - u0 = BigInts.modmul(u0, u2, p); - u0 = u0.add(p.sub(w)).mod(p); - - t = BigInts.modmul(t, u0, p); - t0 = BigInts.modmul(t0, u3, p); - - y2 = t.add(p.sub(t0)).mod(p); - - z2 = BigInts.modmul(u3, v, p); - } - - function _isZeroCurve(BigInt memory x, BigInt memory y) internal view returns (bool) { - return x.eq(zero) && y.eq(zero); - } - - function _zeroProj() internal view returns (BigInt memory, BigInt memory, BigInt memory) { - return (zero, one, zero); - } - - function _zeroAffine() internal view returns (BigInt memory, BigInt memory) { - return (zero, zero); - } -} diff --git a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol b/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol deleted file mode 100644 index 2f2890b..0000000 --- a/contracts/passport/authenticators/PECDSASHA2NewAuthenticator.sol +++ /dev/null @@ -1,600 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.17; - -import "hardhat/console.sol"; -import {SharedMemory, MemoryUint} from "../../utils/MemoryUint.sol"; -import {SHA1} from "../../utils/SHA1.sol"; - -/** - * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol - */ -contract PECDSASHA2NewAuthenticator { - using MemoryUint for *; - using SHA1 for bytes; - - // secp384r1 parameters - struct Secp384rParams { - uint256 a; - uint256 b; - uint256 gx; - uint256 gy; - uint256 p; - uint256 n; - uint256 lowSmax; - } - - struct XYZ { - uint256 x; - uint256 y; - uint256 z; - } - - struct UT { - uint256 u0; - uint256 u1; - uint256 t0; - uint256 t1; - } - - struct UWT { - uint256 u; - uint256 u2; - uint256 u3; - uint256 w; - uint256 t; - } - - struct TUVW { - uint256 t; - uint256 u; - uint256 v; - uint256 w; - } - - /** - * @notice Checks active authentication of a passport. ECDSA active authentication is an ECDSA signature of - * raw SHA2 hash of challenge bytes. Usually brainpool256r1 elliptic curve is used. - */ - function authenticate( - bytes memory challenge, - bytes memory r, - bytes memory s, - bytes memory x, - bytes memory y - ) external view returns (bool) { - SharedMemory memory _shMem = MemoryUint.newUint512SharedMemory(); - Secp384rParams memory _params = Secp384rParams({ - a: _shMem.newUint512( - hex"7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9" - ), - b: _shMem.newUint512( - hex"26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6" - ), - gx: _shMem.newUint512( - hex"8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262" - ), - gy: _shMem.newUint512( - hex"547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997" - ), - p: _shMem.newUint512( - hex"A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377" - ), - n: _shMem.newUint512( - hex"A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7" - ), - lowSmax: _shMem.newUint512( - hex"54fdabedd0f754de1f3305484ec1c6b9371dfb11ea9310141009a40e8fb729bb" - ) - }); - - uint256 _x = _shMem.newUint512(x); - uint256 _y = _shMem.newUint512(y); - - /// @dev accept s only from the lower part of the curve - // if (r == 0 || r >= n || s == 0 || s > lowSmax) { - // return false; - // } - - if (!_isOnCurve(_shMem, _params, _x, _y)) { - return false; - } - - uint256 message = _shMem.newUint512(abi.encodePacked(uint160(challenge.sha1()))); - uint256 temp = _shMem.moddiv( - message, - _shMem.newUint512(s), - _params.n, - MemoryUint.Destructor.SECOND - ); - - (uint256 x1, uint256 y1) = _multiplyScalar(_shMem, _params, _params.gx, _params.gy, temp); - - _shMem.destruct(temp); - - console.logBytes(MemoryUint.toData(x1)); - console.logBytes(MemoryUint.toData(y1)); - - return false; - - // uint256 _r = _shMem.newUint512(r); - - // temp = _shMem.moddiv(_r, _s, _params.n); - // (uint256 x2, uint256 y2) = _multiplyScalar(_shMem, _params, _x, _y, temp); - // _shMem.destruct(temp); - - // _shMem.destruct(_s); - - // uint256 x1 = _shMem.newUint512( - // hex"237544e26b27436fe2825685b0c8c479b5a9fba1424eed1bdb46662edf7357a7" - // ); - // uint256 x2 = _shMem.newUint512( - // hex"09e5dd89d2c91b8e803a1582af8835ef03824a43cbcd4cb7320b1aa675706add" - // ); - // uint256 y1 = _shMem.newUint512( - // hex"5c746bb1eaef6275433511fbc7afa832abd79e58d7b06fe63104696f957e47fc" - // ); - // uint256 y2 = _shMem.newUint512( - // hex"8fd8e0c00ea0ca899cbd668e8de533e5cadb188a3d37a633b953501196194f39" - // ); - - // Uint512[3] memory P = _addAndReturnProjectivePoint(_shMem, _params, x1, y1, x2, y2); - - // _shMem.destruct(x1); - // _shMem.destruct(x2); - // _shMem.destruct(y1); - // _shMem.destruct(y2); - - // uint256 temp = _shMem.zero(); - // if (_shMem.cmp(P[2], temp) == 0) { - // return false; - // } - // _shMem.destruct(temp); - - // temp = _shMem.moddiv(P[2], P[2], _params.p); - // uint256 Px = _shMem.modmul(P[0], temp, _params.p); - // _shMem.destruct(temp); - - // temp = _shMem.mod(Px, _params.n); - - // return _shMem.cmp(temp, _r) == 0; - } - - /** - * @dev Multiply an elliptic curve point by a scalar. - */ - function _multiplyScalar( - SharedMemory memory shMem, - Secp384rParams memory params, - uint256 x0, - uint256 y0, - uint256 scalar - ) internal view returns (uint256 x1, uint256 y1) { - { - uint256 zero = shMem.zero(); - uint256 one = shMem.one(); - - if (shMem.cmp(scalar, zero) == 0) { - return _zeroAffine(shMem); - } else if (shMem.cmp(scalar, one) == 0) { - return (x0, y0); - } else { - uint256 two = shMem.two(); - int256 res = shMem.cmp(scalar, two); - - shMem.destruct(two); - - if (res == 0) { - return _twice(shMem, params, x0, y0); - } - } - } - - XYZ memory xyzBase; - XYZ memory xyz1; - XYZ memory temp; - - { - bytes memory x0Bytes; - bytes memory y0Bytes; - - assembly { - x0Bytes := x0 - y0Bytes := y0 - } - - xyzBase = XYZ(shMem.newUint512(x0Bytes), shMem.newUint512(y0Bytes), shMem.one()); - xyz1 = XYZ(shMem.newUint512(x0Bytes), shMem.newUint512(y0Bytes), shMem.one()); - } - - uint256 lowBits_; - - assembly { - lowBits_ := mload(add(scalar, 0x40)) - } - - lowBits_ = lowBits_ >> 1; - - // while (lowBits_ > 0) { - for (uint256 i = 0; i < 10; i++) { - temp = _twiceProj(shMem, params, xyzBase); - - shMem.destruct(xyzBase.x); - shMem.destruct(xyzBase.y); - shMem.destruct(xyzBase.z); - - xyzBase = temp; - - if (lowBits_ & 1 == 1) { - temp = _addProj(shMem, params, xyzBase, xyz1); - - shMem.destruct(xyz1.x); - shMem.destruct(xyz1.y); - shMem.destruct(xyz1.z); - - xyz1 = temp; - } - - lowBits_ = lowBits_ >> 1; - - uint256 mem_; - - assembly { - mem_ := msize() - } - - console.log(mem_); - } - - shMem.destruct(xyzBase.x); - shMem.destruct(xyzBase.y); - shMem.destruct(xyzBase.z); - - (x1, y1) = _toAffinePoint(shMem, params, xyz1); - - shMem.destruct(xyz1.x); - shMem.destruct(xyz1.y); - shMem.destruct(xyz1.z); - } - - /** - * @dev Double an elliptic curve point in projective coordinates. See - * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates - */ - function _twiceProj( - SharedMemory memory shMem, - Secp384rParams memory params, - XYZ memory xyz0 - ) internal view returns (XYZ memory xyz) { - TUVW memory tuvw; - - if (_isZeroCurve(shMem, xyz0.x, xyz0.y)) { - return _zeroProj(shMem); - } - - uint256 two = shMem.two(); - - tuvw.u = shMem.modmul(xyz0.y, xyz0.z, params.p); - tuvw.u = shMem.modmul(tuvw.u, two, params.p, MemoryUint.Destructor.FIRST); - - tuvw.v = shMem.modmul(tuvw.u, xyz0.x, params.p); - tuvw.v = shMem.modmul(tuvw.v, xyz0.y, params.p, MemoryUint.Destructor.FIRST); - tuvw.v = shMem.modmul(tuvw.v, two, params.p, MemoryUint.Destructor.FIRST); - - xyz0.x = shMem.modmul(xyz0.x, xyz0.x, params.p, MemoryUint.Destructor.FIRST); - - tuvw.t = shMem.modmul(xyz0.x, shMem.three(), params.p, MemoryUint.Destructor.BOTH); - - xyz0.z = shMem.modmul(xyz0.z, xyz0.z, params.p, MemoryUint.Destructor.FIRST); - xyz0.z = shMem.modmul(xyz0.z, params.a, params.p, MemoryUint.Destructor.FIRST); - - tuvw.t = shMem.modadd(tuvw.t, xyz0.z, params.p, MemoryUint.Destructor.FIRST); - tuvw.w = shMem.modmul(tuvw.t, tuvw.t, params.p); - - xyz0.x = shMem.modmul(two, tuvw.v, params.p); - - tuvw.w = shMem.modadd( - tuvw.w, - shMem.sub(params.p, xyz0.x), - params.p, - MemoryUint.Destructor.BOTH - ); - - xyz0.x = shMem.modadd( - tuvw.v, - shMem.sub(params.p, tuvw.w), - params.p, - MemoryUint.Destructor.SECOND - ); - xyz0.x = shMem.modmul(tuvw.t, xyz0.x, params.p, MemoryUint.Destructor.SECOND); - xyz0.y = shMem.modmul(xyz0.y, tuvw.u, params.p, MemoryUint.Destructor.FIRST); - xyz0.y = shMem.modmul(xyz0.y, xyz0.y, params.p, MemoryUint.Destructor.FIRST); - xyz0.y = shMem.modmul(two, xyz0.y, params.p, MemoryUint.Destructor.BOTH); - - xyz.y = shMem.modadd( - xyz0.x, - shMem.sub(params.p, xyz0.y), - params.p, - MemoryUint.Destructor.SECOND - ); - xyz.x = shMem.modmul(tuvw.u, tuvw.w, params.p); - xyz.z = shMem.modmul(tuvw.u, tuvw.u, params.p); - xyz.z = shMem.modmul(xyz.z, tuvw.u, params.p, MemoryUint.Destructor.FIRST); - - shMem.destruct(tuvw.t); - shMem.destruct(tuvw.u); - shMem.destruct(tuvw.v); - shMem.destruct(tuvw.w); - } - - /** - * @dev Add two elliptic curve points in projective coordinates. See - * https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates - */ - function _addProj( - SharedMemory memory shMem, - Secp384rParams memory params, - XYZ memory xyz0, - XYZ memory xyz1 - ) internal view returns (XYZ memory xyz) { - if (_isZeroCurve(shMem, xyz0.x, xyz0.y)) { - return XYZ(xyz1.x, xyz1.y, xyz1.z); // FIXME copy - } else if (_isZeroCurve(shMem, xyz1.x, xyz1.y)) { - return XYZ(xyz0.x, xyz0.y, xyz0.z); // FIXME copy - } - - UT memory ut; - - ut.t0 = shMem.modmul(xyz0.y, xyz1.z, params.p); - ut.t1 = shMem.modmul(xyz1.y, xyz0.z, params.p); - - ut.u0 = shMem.modmul(xyz0.x, xyz1.z, params.p); - ut.u1 = shMem.modmul(xyz1.x, xyz0.z, params.p); - - if (shMem.cmp(ut.u0, ut.u1) == 0) { - if (shMem.cmp(ut.t0, ut.t1) == 0) { - xyz = _twiceProj(shMem, params, xyz0); - } else { - xyz = _zeroProj(shMem); - } - } else { - xyz = _addProj2(shMem, params, shMem.modmul(xyz0.z, xyz1.z, params.p), ut); - } - - shMem.destruct(ut.t0); - shMem.destruct(ut.t1); - shMem.destruct(ut.u0); - shMem.destruct(ut.u1); - } - - /** - * @dev Helper function that splits addProj to avoid too many local variables. - */ - function _addProj2( - SharedMemory memory shMem, - Secp384rParams memory params, - uint256 v, - UT memory ut - ) internal view returns (XYZ memory xyz) { - UWT memory uwt; - - uwt.t = shMem.modadd( - ut.t0, - shMem.sub(params.p, ut.t1), - params.p, - MemoryUint.Destructor.SECOND - ); - uwt.u = shMem.modadd( - ut.u0, - shMem.sub(params.p, ut.u1), - params.p, - MemoryUint.Destructor.SECOND - ); - - uwt.u2 = shMem.modmul(uwt.u, uwt.u, params.p); - uwt.w = shMem.modmul(uwt.t, uwt.t, params.p); - uwt.w = shMem.modmul(uwt.w, v, params.p, MemoryUint.Destructor.FIRST); - - ut.u1 = shMem.modadd(ut.u1, ut.u0, params.p, MemoryUint.Destructor.FIRST); - ut.u1 = shMem.modmul(ut.u1, uwt.u2, params.p, MemoryUint.Destructor.FIRST); - - uwt.w = shMem.modadd( - uwt.w, - shMem.sub(params.p, ut.u1), - params.p, - MemoryUint.Destructor.BOTH - ); - - xyz.x = shMem.modmul(uwt.u, uwt.w, params.p); - - uwt.u3 = shMem.modmul(uwt.u2, uwt.u, params.p); - - ut.u0 = shMem.modmul(ut.u0, uwt.u2, params.p, MemoryUint.Destructor.FIRST); - ut.u0 = shMem.modadd( - ut.u0, - shMem.sub(params.p, uwt.w), - params.p, - MemoryUint.Destructor.BOTH - ); - - uwt.t = shMem.modmul(uwt.t, ut.u0, params.p, MemoryUint.Destructor.FIRST); - - ut.t0 = shMem.modmul(ut.t0, uwt.u3, params.p, MemoryUint.Destructor.FIRST); - - xyz.y = shMem.modadd( - uwt.t, - shMem.sub(params.p, ut.t0), - params.p, - MemoryUint.Destructor.SECOND - ); - xyz.z = shMem.modmul(uwt.u3, v, params.p, MemoryUint.Destructor.SECOND); - - shMem.destruct(uwt.u); - shMem.destruct(uwt.u2); - shMem.destruct(uwt.u3); - shMem.destruct(uwt.w); - shMem.destruct(uwt.t); - } - - /** - * @dev Add two elliptic curve points in affine coordinates. - */ - function _add( - SharedMemory memory shMem, - Secp384rParams memory params, - uint256 x0, - uint256 y0, - uint256 x1, - uint256 y1 - ) internal view returns (uint256 x, uint256 y) { - uint256 one = shMem.one(); - - XYZ memory xyz = _addProj(shMem, params, XYZ(x0, y0, one), XYZ(x1, y1, one)); - (x, y) = _toAffinePoint(shMem, params, xyz); - - shMem.destruct(one); - shMem.destruct(xyz.x); - shMem.destruct(xyz.y); - shMem.destruct(xyz.z); - } - - /** - * @dev Double an elliptic curve point in affine coordinates. - */ - function _twice( - SharedMemory memory shMem, - Secp384rParams memory params, - uint256 x0, - uint256 y0 - ) internal view returns (uint256 x, uint256 y) { - uint256 one = shMem.one(); - - XYZ memory xyz = _twiceProj(shMem, params, XYZ(x0, y0, one)); - - (x, y) = _toAffinePoint(shMem, params, xyz); - - shMem.destruct(one); - shMem.destruct(xyz.x); - shMem.destruct(xyz.y); - shMem.destruct(xyz.z); - } - - /** - * @dev Add two points in affine coordinates and return projective point. - */ - function _addAndReturnProjectivePoint( - SharedMemory memory shMem, - Secp384rParams memory params, - uint256 x1, - uint256 y1, - uint256 x2, - uint256 y2 - ) internal view returns (uint256[3] memory P) { - (uint256 x, uint256 y) = _add(shMem, params, x1, y1, x2, y2); - P = _toProjectivePoint(shMem, params, x, y); - - shMem.destruct(x); - shMem.destruct(y); - } - - /** - * @dev Transform from projective to affine coordinates. - */ - function _toAffinePoint( - SharedMemory memory shMem, - Secp384rParams memory params, - XYZ memory xyz - ) internal view returns (uint256 x1, uint256 y1) { - x1 = shMem.moddiv(xyz.x, xyz.z, params.p); - y1 = shMem.moddiv(xyz.y, xyz.z, params.p); - } - - /** - * @dev Check if a point in affine coordinates is on the curve. - */ - function _isOnCurve( - SharedMemory memory shMem, - Secp384rParams memory params, - uint256 x, - uint256 y - ) internal view returns (bool res) { - uint256 zero = shMem.zero(); - - if ( - shMem.cmp(x, zero) == 0 || - shMem.cmp(y, zero) == 0 || - shMem.cmp(x, params.p) == 0 || - shMem.cmp(y, params.p) == 0 - ) { - return false; - } - - uint256 RHS = shMem.modmul( - shMem.modmul(x, x, params.p), - x, - params.p, - MemoryUint.Destructor.FIRST - ); // x^3 - uint256 LHS = shMem.modmul(y, y, params.p); // y^2x - - if (shMem.cmp(params.a, zero) != 0) { - RHS = shMem.modadd( - RHS, - shMem.modmul(x, params.a, params.p), - params.p, - MemoryUint.Destructor.BOTH - ); // x^3 + a*x - } - - if (shMem.cmp(params.b, zero) != 0) { - RHS = shMem.modadd(RHS, params.b, params.p, MemoryUint.Destructor.FIRST); // x^3 + a*x + b - } - - res = shMem.cmp(LHS, RHS) == 0; - - shMem.destruct(zero); - shMem.destruct(LHS); - shMem.destruct(RHS); - } - - /** - * @dev Transform affine coordinates into projective coordinates. - */ - function _toProjectivePoint( - SharedMemory memory shMem, - Secp384rParams memory params, - uint256 x0, - uint256 y0 - ) internal view returns (uint256[3] memory P) { - P[2] = shMem.one(); - P[0] = shMem.modmul(x0, P[2], params.p); - P[1] = shMem.modmul(y0, P[2], params.p); - } - - /** - * @dev Return the zero curve in projective coordinates. - */ - function _zeroProj(SharedMemory memory shMem) internal view returns (XYZ memory) { - return XYZ(shMem.zero(), shMem.one(), shMem.zero()); - } - - /** - * @dev Return the zero curve in affine coordinates. - */ - function _zeroAffine(SharedMemory memory shMem) internal view returns (uint256 x, uint256 y) { - return (shMem.zero(), shMem.zero()); - } - - /** - * @dev Check if the curve is the zero curve. - */ - function _isZeroCurve( - SharedMemory memory shMem, - uint256 x0, - uint256 y0 - ) internal view returns (bool isZero) { - uint256 zero = shMem.zero(); - isZero = shMem.cmp(x0, zero) == 0 && shMem.cmp(y0, zero) == 0; - - shMem.destruct(zero); - } -} diff --git a/contracts/utils/BigInt.sol b/contracts/utils/BigInt.sol deleted file mode 100644 index 24905ab..0000000 --- a/contracts/utils/BigInt.sol +++ /dev/null @@ -1,1309 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.17; - -import "hardhat/console.sol"; -// Definition here allows both the lib and inheriting contracts to use BigInt directly. -struct BigInt { - bytes val; - bool neg; - uint bitlen; -} - -/** - * @notice BigInts library for Solidity. - */ -library BigInts { - /// @notice the value for number 0 of a BigInt instance. - bytes constant ZERO = hex"0000000000000000000000000000000000000000000000000000000000000000"; - /// @notice the value for number 1 of a BigInt instance. - bytes constant ONE = hex"0000000000000000000000000000000000000000000000000000000000000001"; - /// @notice the value for number 2 of a BigInt instance. - bytes constant TWO = hex"0000000000000000000000000000000000000000000000000000000000000002"; - - // ***************** BEGIN EXPOSED MANAGEMENT FUNCTIONS ****************** - /** @notice verify a BN instance - * @dev checks if the BN is in the correct format. operations should only be carried out on - * verified BNs, so it is necessary to call this if your function takes an arbitrary BN - * as input. - * - * @param bn BigInt instance - */ - function verify( - BigInt memory bn - ) internal pure { - uint msword; - bytes memory val = bn.val; - assembly {msword := mload(add(val,0x20))} //get msword of result - if(msword==0) require(isZero(bn)); - else require((bn.val.length % 32 == 0) && (msword>>((bn.bitlen-1)%256)==1)); - } - - /** @notice initialize a BN instance - * @dev wrapper function for _init. initializes from bytes value. - * Allows passing bitLength of value. This is NOT verified in the internal function. Only use where bitlen is - * explicitly known; otherwise use the other init function. - * - * @param val BN value. may be of any size. - * @param neg neg whether the BN is +/- - * @param bitlen bit length of output. - * @return BigInt instance - */ - function init( - bytes memory val, - bool neg, - uint bitlen - ) internal view returns(BigInt memory){ - return _init(val, neg, bitlen); - } - - /** @notice initialize a BN instance - * @dev wrapper function for _init. initializes from bytes value. - * - * @param val BN value. may be of any size. - * @param neg neg whether the BN is +/- - * @return BigInt instance - */ - function init( - bytes memory val, - bool neg - ) internal view returns(BigInt memory){ - return _init(val, neg, 0); - } - - /** @notice initialize a BN instance - * @dev wrapper function for _init. initializes from uint value (converts to bytes); - * tf. resulting BN is in the range -2^256-1 ... 2^256-1. - * - * @param val uint value. - * @param neg neg whether the BN is +/- - * @return BigInt instance - */ - function init( - uint val, - bool neg - ) internal view returns(BigInt memory){ - return _init(abi.encodePacked(val), neg, 0); - } - // ***************** END EXPOSED MANAGEMENT FUNCTIONS ****************** - - - - - // ***************** BEGIN EXPOSED CORE CALCULATION FUNCTIONS ****************** - /** @notice BigInt addition: a + b. - * @dev add: Initially prepare BigInts for addition operation; internally calls actual addition/subtraction, - * depending on inputs. - * In order to do correct addition or subtraction we have to handle the sign. - * This function discovers the sign of the result based on the inputs, and calls the correct operation. - * - * @param a first BN - * @param b second BN - * @return r result - addition of a and b. - */ - function add( - BigInt memory a, - BigInt memory b - ) internal pure returns(BigInt memory r) { - if(a.bitlen==0 && b.bitlen==0) return zero(); - if(a.bitlen==0) return b; - if(b.bitlen==0) return a; - bytes memory val; - uint bitlen; - int compare = cmp(a,b,false); - - if(a.neg || b.neg){ - if(a.neg && b.neg){ - if(compare>=0) (val, bitlen) = _add(a.val,b.val,a.bitlen); - else (val, bitlen) = _add(b.val,a.val,b.bitlen); - r.neg = true; - } - else { - if(compare==1){ - (val, bitlen) = _sub(a.val,b.val); - r.neg = a.neg; - } - else if(compare==-1){ - (val, bitlen) = _sub(b.val,a.val); - r.neg = !a.neg; - } - else return zero();//one pos and one neg, and same value. - } - } - else{ - if(compare>=0){ // a>=b - (val, bitlen) = _add(a.val,b.val,a.bitlen); - } - else { - (val, bitlen) = _add(b.val,a.val,b.bitlen); - } - r.neg = false; - } - - r.val = val; - r.bitlen = (bitlen); - } - - /** @notice BigInt subtraction: a - b. - * @dev sub: Initially prepare BigInts for subtraction operation; internally calls actual addition/subtraction, - depending on inputs. - * In order to do correct addition or subtraction we have to handle the sign. - * This function discovers the sign of the result based on the inputs, and calls the correct operation. - * - * @param a first BN - * @param b second BN - * @return r result - subtraction of a and b. - */ - function sub( - BigInt memory a, - BigInt memory b - ) internal pure returns(BigInt memory r) { - if(a.bitlen==0 && b.bitlen==0) return zero(); - bytes memory val; - int compare; - uint bitlen; - compare = cmp(a,b,false); - if(a.neg || b.neg) { - if(a.neg && b.neg){ - if(compare == 1) { - (val,bitlen) = _sub(a.val,b.val); - r.neg = true; - } - else if(compare == -1) { - - (val,bitlen) = _sub(b.val,a.val); - r.neg = false; - } - else return zero(); - } - else { - if(compare >= 0) (val,bitlen) = _add(a.val,b.val,a.bitlen); - else (val,bitlen) = _add(b.val,a.val,b.bitlen); - - r.neg = (a.neg) ? true : false; - } - } - else { - if(compare == 1) { - (val,bitlen) = _sub(a.val,b.val); - r.neg = false; - } - else if(compare == -1) { - (val,bitlen) = _sub(b.val,a.val); - r.neg = true; - } - else return zero(); - } - - r.val = val; - r.bitlen = (bitlen); - } - - /** @notice BigInt multiplication: a * b. - * @dev mul: takes two BigInts and multiplys them. Order is irrelevant. - * multiplication achieved using modexp precompile: - * (a * b) = ((a + b)**2 - (a - b)**2) / 4 - * - * @param a first BN - * @param b second BN - * @return r result - multiplication of a and b. - */ - function mul( - BigInt memory a, - BigInt memory b - ) internal view returns(BigInt memory r){ - - BigInt memory lhs = add(a,b); - BigInt memory fst = modexp(lhs, two(), _powModulus(lhs, 2)); // (a+b)^2 - - // no need to do subtraction part of the equation if a == b; if so, it has no effect on final result. - if(!eq(a,b)) { - BigInt memory rhs = sub(a,b); - BigInt memory snd = modexp(rhs, two(), _powModulus(rhs, 2)); // (a-b)^2 - r = _shr(sub(fst, snd) , 2); // (a * b) = (((a + b)**2 - (a - b)**2) / 4 - } - else { - r = _shr(fst, 2); // a==b ? (((a + b)**2 / 4 - } - } - - /** @notice BigInt division verification: a * b. - * @dev div: takes three BigInts (a,b and result), and verifies that a/b == result. - * Performing BigInt division on-chain is a significantly expensive operation. As a result, - * we expose the ability to verify the result of a division operation, which is a constant time operation. - * (a/b = result) == (a = b * result) - * Integer division only; therefore: - * verify ((b*result) + (a % (b*result))) == a. - * eg. 17/7 == 2: - * verify (7*2) + (17 % (7*2)) == 17. - * The function returns a bool on successful verification. The require statements will ensure that false can never - * be returned, however inheriting contracts may also want to put this function inside a require statement. - * - * @param a first BigInt - * @param b second BigInt - * @param r result BigInt - * @return bool whether or not the operation was verified - */ - function divVerify( - BigInt memory a, - BigInt memory b, - BigInt memory r - ) internal view returns(bool) { - - // first do zero check. - // if ab. - * - * @param a BigInt - * @param b BigInt - * @param signed whether to consider sign of inputs - * @return int result - */ - function cmp( - BigInt memory a, - BigInt memory b, - bool signed - ) internal pure returns(int){ - int trigger = 1; - if(signed){ - if(a.neg && b.neg) trigger = -1; - else if(a.neg==false && b.neg==true) return 1; - else if(a.neg==true && b.neg==false) return -1; - } - - if(a.bitlen>b.bitlen) return trigger; // 1*trigger - if(b.bitlen>a.bitlen) return -1*trigger; - - uint a_ptr; - uint b_ptr; - uint a_word; - uint b_word; - - uint len = a.val.length; //bitlen is same so no need to check length. - - assembly{ - a_ptr := add(mload(a),0x20) - b_ptr := add(mload(b),0x20) - } - - for(uint i=0; ib_word) return trigger; // 1*trigger - if(b_word>a_word) return -1*trigger; - - } - - return 0; //same value. - } - - /** @notice BigInt equality - * @dev eq: returns true if a==b. sign always considered. - * - * @param a BigInt - * @param b BigInt - * @return boolean result - */ - function eq( - BigInt memory a, - BigInt memory b - ) internal pure returns(bool){ - int result = cmp(a, b, true); - return (result==0) ? true : false; - } - - /** @notice BigInt greater than - * @dev eq: returns true if a>b. sign always considered. - * - * @param a BigInt - * @param b BigInt - * @return boolean result - */ - function gt( - BigInt memory a, - BigInt memory b - ) internal pure returns(bool){ - int result = cmp(a, b, true); - return (result==1) ? true : false; - } - - /** @notice BigInt greater than or equal to - * @dev eq: returns true if a>=b. sign always considered. - * - * @param a BigInt - * @param b BigInt - * @return boolean result - */ - function gte( - BigInt memory a, - BigInt memory b - ) internal pure returns(bool){ - int result = cmp(a, b, true); - return (result==1 || result==0) ? true : false; - } - - /** @notice BigInt less than - * @dev eq: returns true if a= the bitlength of the value the result is always 0 - if(bits >= bn.bitlen) return BigInt(ZERO,false,0); - - // set bitlen initially as we will be potentially modifying 'bits' - bn.bitlen = bn.bitlen-(bits); - - // handle shifts greater than 256: - // if bits is greater than 256 we can simply remove any trailing words, by altering the BN length. - // we also update 'bits' so that it is now in the range 0..256. - assembly { - if or(gt(bits, 0x100), eq(bits, 0x100)) { - length := sub(length, mul(div(bits, 0x100), 0x20)) - mstore(mload(bn), length) - bits := mod(bits, 0x100) - } - - // if bits is multiple of 8 (byte size), we can simply use identity precompile for cheap memcopy. - // otherwise we shift each word, starting at the least signifcant word, one-by-one using the mask technique. - // TODO it is possible to do this without the last two operations, see SHL identity copy. - let bn_val_ptr := mload(bn) - switch eq(mod(bits, 8), 0) - case 1 { - let bytes_shift := div(bits, 8) - let in := mload(bn) - let inlength := mload(in) - let insize := add(inlength, 0x20) - let out := add(in, bytes_shift) - let outsize := sub(insize, bytes_shift) - let success := staticcall(450, 0x4, in, insize, out, insize) - mstore8(add(out, 0x1f), 0) // maintain our BN layout following identity call: - mstore(in, inlength) // set current length byte to 0, and reset old length. - } - default { - let mask - let lsw - let mask_shift := sub(0x100, bits) - let lsw_ptr := add(bn_val_ptr, length) - for { let i := length } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) - switch eq(i,0x20) // if i==32: - case 1 { mask := 0 } // - handles lsword: no mask needed. - default { mask := mload(sub(lsw_ptr,0x20)) } // - else get mask (previous word) - lsw := shr(bits, mload(lsw_ptr)) // right shift current by bits - mask := shl(mask_shift, mask) // left shift next significant word by mask_shift - mstore(lsw_ptr, or(lsw,mask)) // store OR'd mask and shifted bits in-place - lsw_ptr := sub(lsw_ptr, 0x20) // point to next bits. - } - } - - // The following removes the leading word containing all zeroes in the result should it exist, - // as well as updating lengths and pointers as necessary. - let msw_ptr := add(bn_val_ptr,0x20) - switch eq(mload(msw_ptr), 0) - case 1 { - mstore(msw_ptr, sub(mload(bn_val_ptr), 0x20)) // store new length in new position - mstore(bn, msw_ptr) // update pointer from bn - } - default {} - } - - - return bn; - } - - /** @notice left shift BigInt value - * @dev shr: left shift BigInt a by 'bits' bits. - ensures the value is not negative before calling the private function. - * @param a BigInt value to shift - * @param bits amount of bits to shift by - * @return result BigInt - */ - function shl( - BigInt memory a, - uint bits - ) internal view returns(BigInt memory){ - require(!a.neg); - return _shl(a, bits); - } - - /** @notice sha3 hash a BigInt. - * @dev hash: takes a BigInt and performs sha3 hash on it. - * we hash each BigInt WITHOUT it's first word - first word is a pointer to the start of the bytes value, - * and so is different for each struct. - * - * @param a BigInt - * @return h bytes32 hash. - */ - function hash( - BigInt memory a - ) internal pure returns(bytes32 h) { - //amount of words to hash = all words of the value and three extra words: neg, bitlen & value length. - assembly { - h := keccak256( add(a,0x20), add (mload(mload(a)), 0x60 ) ) - } - } - - /** @notice BigInt full zero check - * @dev isZero: checks if the BigInt is in the default zero format for BNs (ie. the result from zero()). - * - * @param a BigInt - * @return boolean result. - */ - function isZero( - BigInt memory a - ) internal pure returns(bool) { - return isZero(a.val) && a.val.length==0x20 && !a.neg && a.bitlen == 0; - } - - - /** @notice bytes zero check - * @dev isZero: checks if input bytes value resolves to zero. - * - * @param a bytes value - * @return boolean result. - */ - function isZero( - bytes memory a - ) internal pure returns(bool) { - uint msword; - uint msword_ptr; - assembly { - msword_ptr := add(a,0x20) - } - for(uint i=0; i 0) return false; - assembly { msword_ptr := add(msword_ptr, 0x20) } - } - return true; - - } - - /** @notice BigInt value bit length - * @dev bitLength: returns BigInt value bit length- ie. log2 (most significant bit of value) - * - * @param a BigInt - * @return uint bit length result. - */ - function bitLength( - BigInt memory a - ) internal pure returns(uint){ - return bitLength(a.val); - } - - /** @notice bytes bit length - * @dev bitLength: returns bytes bit length- ie. log2 (most significant bit of value) - * - * @param a bytes value - * @return r uint bit length result. - */ - function bitLength( - bytes memory a - ) internal pure returns(uint r){ - if(isZero(a)) return 0; - uint msword; - assembly { - msword := mload(add(a,0x20)) // get msword of input - } - r = bitLength(msword); // get bitlen of msword, add to size of remaining words. - assembly { - r := add(r, mul(sub(mload(a), 0x20) , 8)) // res += (val.length-32)*8; - } - } - - /** @notice uint bit length - @dev bitLength: get the bit length of a uint input - ie. log2 (most significant bit of 256 bit value (one EVM word)) - * credit: Tjaden Hess @ ethereum.stackexchange - * @param a uint value - * @return r uint bit length result. - */ - function bitLength( - uint a - ) internal pure returns (uint r){ - assembly { - switch eq(a, 0) - case 1 { - r := 0 - } - default { - let arg := a - a := sub(a,1) - a := or(a, div(a, 0x02)) - a := or(a, div(a, 0x04)) - a := or(a, div(a, 0x10)) - a := or(a, div(a, 0x100)) - a := or(a, div(a, 0x10000)) - a := or(a, div(a, 0x100000000)) - a := or(a, div(a, 0x10000000000000000)) - a := or(a, div(a, 0x100000000000000000000000000000000)) - a := add(a, 1) - let m := mload(0x40) - mstore(m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd) - mstore(add(m,0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe) - mstore(add(m,0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616) - mstore(add(m,0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff) - mstore(add(m,0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e) - mstore(add(m,0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707) - mstore(add(m,0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606) - mstore(add(m,0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100) - mstore(0x40, add(m, 0x100)) - let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff - let shift := 0x100000000000000000000000000000000000000000000000000000000000000 - let _a := div(mul(a, magic), shift) - r := div(mload(add(m,sub(255,_a))), shift) - r := add(r, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000))) - // where a is a power of two, result needs to be incremented. we use the power of two trick here: if(arg & arg-1 == 0) ++r; - if eq(and(arg, sub(arg, 1)), 0) { - r := add(r, 1) - } - } - } - } - - /** @notice BigInt zero value - @dev zero: returns zero encoded as a BigInt - * @return zero encoded as BigInt - */ - function zero( - ) internal pure returns(BigInt memory) { - return BigInt(ZERO, false, 0); - } - - /** @notice BigInt one value - @dev one: returns one encoded as a BigInt - * @return one encoded as BigInt - */ - function one( - ) internal pure returns(BigInt memory) { - return BigInt(ONE, false, 1); - } - - /** @notice BigInt two value - @dev two: returns two encoded as a BigInt - * @return two encoded as BigInt - */ - function two( - ) internal pure returns(BigInt memory) { - return BigInt(TWO, false, 2); - } - // ***************** END EXPOSED HELPER FUNCTIONS ****************** - - - - - - // ***************** START PRIVATE MANAGEMENT FUNCTIONS ****************** - /** @notice Create a new BigInt. - @dev init: overloading allows caller to obtionally pass bitlen where it is known - as it is cheaper to do off-chain and verify on-chain. - * we assert input is in data structure as defined above, and that bitlen, if passed, is correct. - * 'copy' parameter indicates whether or not to copy the contents of val to a new location in memory (for example where you pass - * the contents of another variable's value in) - * @param val bytes - bignum value. - * @param neg bool - sign of value - * @param bitlen uint - bit length of value - * @return r BigInt initialized value. - */ - function _init( - bytes memory val, - bool neg, - uint bitlen - ) private view returns(BigInt memory r){ - // use identity at location 0x4 for cheap memcpy. - // grab contents of val, load starting from memory end, update memory end pointer. - assembly { - let data := add(val, 0x20) - let length := mload(val) - let out - let freemem := mload(0x40) - switch eq(mod(length, 0x20), 0) // if(val.length % 32 == 0) - case 1 { - out := add(freemem, 0x20) // freememory location + length word - mstore(freemem, length) // set new length - } - default { - let offset := sub(0x20, mod(length, 0x20)) // offset: 32 - (length % 32) - out := add(add(freemem, offset), 0x20) // freememory location + offset + length word - mstore(freemem, add(length, offset)) // set new length - } - pop(staticcall(450, 0x4, data, length, out, length)) // copy into 'out' memory location - mstore(0x40, add(freemem, add(mload(freemem), 0x20))) // update the free memory pointer - - // handle leading zero words. assume freemem is pointer to bytes value - let bn_length := mload(freemem) - for { } eq ( eq(bn_length, 0x20), 0) { } { // for(; length!=32; length-=32) - switch eq(mload(add(freemem, 0x20)),0) // if(msword==0): - case 1 { freemem := add(freemem, 0x20) } // update length pointer - default { break } // else: loop termination. non-zero word found - bn_length := sub(bn_length,0x20) - } - mstore(freemem, bn_length) - - mstore(r, freemem) // store new bytes value in r - mstore(add(r, 0x20), neg) // store neg value in r - } - - r.bitlen = bitlen == 0 ? bitLength(r.val) : bitlen; - } - // ***************** END PRIVATE MANAGEMENT FUNCTIONS ****************** - - - - - - // ***************** START PRIVATE CORE CALCULATION FUNCTIONS ****************** - /** @notice takes two BigInt memory values and the bitlen of the max value, and adds them. - * @dev _add: This function is private and only callable from add: therefore the values may be of different sizes, - * in any order of size, and of different signs (handled in add). - * As values may be of different sizes, inputs are considered starting from the least significant - * words, working back. - * The function calculates the new bitlen (basically if bitlens are the same for max and min, - * max_bitlen++) and returns a new BigInt memory value. - * - * @param max bytes - biggest value (determined from add) - * @param min bytes - smallest value (determined from add) - * @param max_bitlen uint - bit length of max value. - * @return bytes result - max + min. - * @return uint - bit length of result. - */ - function _add( - bytes memory max, - bytes memory min, - uint max_bitlen - ) private pure returns (bytes memory, uint) { - bytes memory result; - assembly { - - let result_start := mload(0x40) // Get the highest available block of memory - let carry := 0 - let uint_max := sub(0,1) - - let max_ptr := add(max, mload(max)) - let min_ptr := add(min, mload(min)) // point to last word of each byte array. - - let result_ptr := add(add(result_start,0x20), mload(max)) // set result_ptr end. - - for { let i := mload(max) } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) - let max_val := mload(max_ptr) // get next word for 'max' - switch gt(i,sub(mload(max),mload(min))) // if(i>(max_length-min_length)). while - // 'min' words are still available. - case 1{ - let min_val := mload(min_ptr) // get next word for 'min' - mstore(result_ptr, add(add(max_val,min_val),carry)) // result_word = max_word+min_word+carry - switch gt(max_val, sub(uint_max,sub(min_val,carry))) // this switch block finds whether or - // not to set the carry bit for the - // next iteration. - case 1 { carry := 1 } - default { - switch and(eq(max_val,uint_max),or(gt(carry,0), gt(min_val,0))) - case 1 { carry := 1 } - default{ carry := 0 } - } - - min_ptr := sub(min_ptr,0x20) // point to next 'min' word - } - default{ // else: remainder after 'min' words are complete. - mstore(result_ptr, add(max_val,carry)) // result_word = max_word+carry - - switch and( eq(uint_max,max_val), eq(carry,1) ) // this switch block finds whether or - // not to set the carry bit for the - // next iteration. - case 1 { carry := 1 } - default { carry := 0 } - } - result_ptr := sub(result_ptr,0x20) // point to next 'result' word - max_ptr := sub(max_ptr,0x20) // point to next 'max' word - } - - switch eq(carry,0) - case 1{ result_start := add(result_start,0x20) } // if carry is 0, increment result_start, ie. - // length word for result is now one word - // position ahead. - default { mstore(result_ptr, 1) } // else if carry is 1, store 1; overflow has - // occured, so length word remains in the - // same position. - - result := result_start // point 'result' bytes value to the correct - // address in memory. - mstore(result,add(mload(max),mul(0x20,carry))) // store length of result. we are finished - // with the byte array. - - mstore(0x40, add(result,add(mload(result),0x20))) // Update freemem pointer to point to new - // end of memory. - - // we now calculate the result's bit length. - // with addition, if we assume that some a is at least equal to some b, then the resulting bit length will - // be a's bit length or (a's bit length)+1, depending on carry bit.this is cheaper than calling bitLength. - let msword := mload(add(result,0x20)) // get most significant word of result - // if(msword==1 || msword>>(max_bitlen % 256)==1): - if or( eq(msword, 1), eq(shr(mod(max_bitlen,256),msword),1) ) { - max_bitlen := add(max_bitlen, 1) // if msword's bit length is 1 greater - // than max_bitlen, OR overflow occured, - // new bitlen is max_bitlen+1. - } - } - - - return (result, max_bitlen); - } - - /** @notice takes two BigInt memory values and subtracts them. - * @dev _sub: This function is private and only callable from add: therefore the values may be of different sizes, - * in any order of size, and of different signs (handled in add). - * As values may be of different sizes, inputs are considered starting from the least significant words, - * working back. - * The function calculates the new bitlen (basically if bitlens are the same for max and min, - * max_bitlen++) and returns a new BigInt memory value. - * - * @param max bytes - biggest value (determined from add) - * @param min bytes - smallest value (determined from add) - * @return bytes result - max + min. - * @return uint - bit length of result. - */ - function _sub( - bytes memory max, - bytes memory min - ) internal pure returns (bytes memory, uint) { - bytes memory result; - uint carry = 0; - uint uint_max = type(uint256).max; - assembly { - - let result_start := mload(0x40) // Get the highest available block of - // memory - - let max_len := mload(max) - let min_len := mload(min) // load lengths of inputs - - let len_diff := sub(max_len,min_len) // get differences in lengths. - - let max_ptr := add(max, max_len) - let min_ptr := add(min, min_len) // go to end of arrays - let result_ptr := add(result_start, max_len) // point to least significant result - // word. - let memory_end := add(result_ptr,0x20) // save memory_end to update free memory - // pointer at the end. - - for { let i := max_len } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) - let max_val := mload(max_ptr) // get next word for 'max' - switch gt(i,len_diff) // if(i>(max_length-min_length)). while - // 'min' words are still available. - case 1{ - let min_val := mload(min_ptr) // get next word for 'min' - - mstore(result_ptr, sub(sub(max_val,min_val),carry)) // result_word = (max_word-min_word)-carry - - switch or(lt(max_val, add(min_val,carry)), - and(eq(min_val,uint_max), eq(carry,1))) // this switch block finds whether or - // not to set the carry bit for the next iteration. - case 1 { carry := 1 } - default { carry := 0 } - - min_ptr := sub(min_ptr,0x20) // point to next 'result' word - } - default { // else: remainder after 'min' words are complete. - - mstore(result_ptr, sub(max_val,carry)) // result_word = max_word-carry - - switch and( eq(max_val,0), eq(carry,1) ) // this switch block finds whether or - // not to set the carry bit for the - // next iteration. - case 1 { carry := 1 } - default { carry := 0 } - - } - result_ptr := sub(result_ptr,0x20) // point to next 'result' word - max_ptr := sub(max_ptr,0x20) // point to next 'max' word - } - - //the following code removes any leading words containing all zeroes in the result. - result_ptr := add(result_ptr,0x20) - - // for(result_ptr+=32;; result==0; result_ptr+=32) - for { } eq(mload(result_ptr), 0) { result_ptr := add(result_ptr,0x20) } { - result_start := add(result_start, 0x20) // push up the start pointer for the result - max_len := sub(max_len,0x20) // subtract a word (32 bytes) from the - // result length. - } - - result := result_start // point 'result' bytes value to - // the correct address in memory - - mstore(result,max_len) // store length of result. we - // are finished with the byte array. - - mstore(0x40, memory_end) // Update freemem pointer. - } - - uint new_bitlen = bitLength(result); // calculate the result's - // bit length. - - return (result, new_bitlen); - } - - /** @notice gets the modulus value necessary for calculating exponetiation. - * @dev _powModulus: we must pass the minimum modulus value which would return JUST the a^b part of the calculation - * in modexp. the rationale here is: - * if 'a' has n bits, then a^e has at most n*e bits. - * using this modulus in exponetiation will result in simply a^e. - * therefore the value may be many words long. - * This is done by: - * - storing total modulus byte length - * - storing first word of modulus with correct bit set - * - updating the free memory pointer to come after total length. - * - * @param a BigInt base - * @param e uint exponent - * @return BigInt modulus result - */ - function _powModulus( - BigInt memory a, - uint e - ) private pure returns(BigInt memory){ - bytes memory _modulus = ZERO; - uint mod_index; - - assembly { - mod_index := mul(mload(add(a, 0x40)), e) // a.bitlen * e is the max bitlength of result - let first_word_modulus := shl(mod(mod_index, 256), 1) // set bit in first modulus word. - mstore(_modulus, mul(add(div(mod_index,256),1),0x20)) // store length of modulus - mstore(add(_modulus,0x20), first_word_modulus) // set first modulus word - mstore(0x40, add(_modulus, add(mload(_modulus),0x20))) // update freemem pointer to be modulus index - // + length - } - - //create modulus BigInt memory for modexp function - return BigInt(_modulus, false, mod_index); - } - - /** @notice Modular Exponentiation: Takes bytes values for base, exp, mod and calls precompile for (base^exp)%^mod - * @dev modexp: Wrapper for built-in modexp (contract 0x5) as described here: - * https://github.com/ethereum/EIPs/pull/198 - * - * @param _b bytes base - * @param _e bytes base_inverse - * @param _m bytes exponent - * @param r bytes result. - */ - function _modexp( - bytes memory _b, - bytes memory _e, - bytes memory _m - ) private view returns(bytes memory r) { - assembly { - - let bl := mload(_b) - let el := mload(_e) - let ml := mload(_m) - - - let freemem := mload(0x40) // Free memory pointer is always stored at 0x40 - - - mstore(freemem, bl) // arg[0] = base.length @ +0 - - mstore(add(freemem,32), el) // arg[1] = exp.length @ +32 - - mstore(add(freemem,64), ml) // arg[2] = mod.length @ +64 - - // arg[3] = base.bits @ + 96 - // Use identity built-in (contract 0x4) as a cheap memcpy - let success := staticcall(450, 0x4, add(_b,32), bl, add(freemem,96), bl) - - // arg[4] = exp.bits @ +96+base.length - let size := add(96, bl) - success := staticcall(450, 0x4, add(_e,32), el, add(freemem,size), el) - - // arg[5] = mod.bits @ +96+base.length+exp.length - size := add(size,el) - success := staticcall(450, 0x4, add(_m,32), ml, add(freemem,size), ml) - - switch success case 0 { invalid() } //fail where we haven't enough gas to make the call - - // Total size of input = 96+base.length+exp.length+mod.length - size := add(size,ml) - // Invoke contract 0x5, put return value right after mod.length, @ +96 - success := staticcall(sub(gas(), 1350), 0x5, freemem, size, add(freemem, 0x60), ml) - - switch success case 0 { invalid() } //fail where we haven't enough gas to make the call - - let length := ml - let msword_ptr := add(freemem, 0x60) - - ///the following code removes any leading words containing all zeroes in the result. - for { } eq ( eq(length, 0x20), 0) { } { // for(; length!=32; length-=32) - switch eq(mload(msword_ptr),0) // if(msword==0): - case 1 { msword_ptr := add(msword_ptr, 0x20) } // update length pointer - default { break } // else: loop termination. non-zero word found - length := sub(length,0x20) - } - r := sub(msword_ptr,0x20) - mstore(r, length) - - // point to the location of the return value (length, bits) - //assuming mod length is multiple of 32, return value is already in the right format. - mstore(0x40, add(add(96, freemem),ml)) //deallocate freemem pointer - } - } - // ***************** END PRIVATE CORE CALCULATION FUNCTIONS ****************** - - - - - - // ***************** START PRIVATE HELPER FUNCTIONS ****************** - /** @notice left shift BigInt memory 'dividend' by 'value' bits. - * @param bn value to shift - * @param bits amount of bits to shift by - * @return r result - */ - function _shl( - BigInt memory bn, - uint bits - ) private view returns(BigInt memory r) { - if(bits==0 || bn.bitlen==0) return bn; - - // we start by creating an empty bytes array of the size of the output, based on 'bits'. - // for that we must get the amount of extra words needed for the output. - uint length = bn.val.length; - // position of bitlen in most significnat word - uint bit_position = ((bn.bitlen-1) % 256) + 1; - // total extra words. we check if the bits remainder will add one more word. - uint extra_words = (bits / 256) + ( (bits % 256) >= (256 - bit_position) ? 1 : 0); - // length of output - uint total_length = length + (extra_words * 0x20); - - r.bitlen = bn.bitlen+(bits); - r.neg = bn.neg; - bits %= 256; - - - bytes memory bn_shift; - uint bn_shift_ptr; - // the following efficiently creates an empty byte array of size 'total_length' - assembly { - let freemem_ptr := mload(0x40) // get pointer to free memory - mstore(freemem_ptr, total_length) // store bytes length - let mem_end := add(freemem_ptr, total_length) // end of memory - mstore(mem_end, 0) // store 0 at memory end - bn_shift := freemem_ptr // set pointer to bytes - bn_shift_ptr := add(bn_shift, 0x20) // get bn_shift pointer - mstore(0x40, add(mem_end, 0x20)) // update freemem pointer - } - - // use identity for cheap copy if bits is multiple of 8. - if(bits % 8 == 0) { - // calculate the position of the first byte in the result. - uint bytes_pos = ((256-(((bn.bitlen-1)+bits) % 256))-1) / 8; - uint insize = (bn.bitlen / 8) + ((bn.bitlen % 8 != 0) ? 1 : 0); - assembly { - let in := add(add(mload(bn), 0x20), div(sub(256, bit_position), 8)) - let out := add(bn_shift_ptr, bytes_pos) - let success := staticcall(450, 0x4, in, insize, out, length) - } - r.val = bn_shift; - return r; - } - - - uint mask; - uint mask_shift = 0x100-bits; - uint msw; - uint msw_ptr; - - assembly { - msw_ptr := add(mload(bn), 0x20) - } - - // handle first word before loop if the shift adds any extra words. - // the loop would handle it if the bit shift doesn't wrap into the next word, - // so we check only for that condition. - if((bit_position+bits) > 256){ - assembly { - msw := mload(msw_ptr) - mstore(bn_shift_ptr, shr(mask_shift, msw)) - bn_shift_ptr := add(bn_shift_ptr, 0x20) - } - } - - // as a result of creating the empty array we just have to operate on the words in the original bn. - for(uint i=bn.val.length; i!=0; i-=0x20){ // for each word: - assembly { - msw := mload(msw_ptr) // get most significant word - switch eq(i,0x20) // if i==32: - case 1 { mask := 0 } // handles msword: no mask needed. - default { mask := mload(add(msw_ptr,0x20)) } // else get mask (next word) - msw := shl(bits, msw) // left shift current msw by 'bits' - mask := shr(mask_shift, mask) // right shift next significant word by mask_shift - mstore(bn_shift_ptr, or(msw,mask)) // store OR'd mask and shifted bits in-place - msw_ptr := add(msw_ptr, 0x20) - bn_shift_ptr := add(bn_shift_ptr, 0x20) - } - } - - r.val = bn_shift; - } - // ***************** END PRIVATE HELPER FUNCTIONS ****************** -} diff --git a/contracts/utils/BigIntOpt.sol b/contracts/utils/BigIntOpt.sol deleted file mode 100644 index b0274ac..0000000 --- a/contracts/utils/BigIntOpt.sol +++ /dev/null @@ -1,1200 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.17; - -import "hardhat/console.sol"; -// DefinitOption here allows both the lib and inheriting contracts to use BigIntOpt directly. -struct BigIntOpt { - bytes val; - bool neg; - uint bitlen; -} - -/** - * @notice BigIntOpts library for Solidity. - */ -library BigIntsOpt { - /// @notice the value for number 0 of a BigIntOpt instance. - bytes constant ZERO = hex"0000000000000000000000000000000000000000000000000000000000000000"; - /// @notice the value for number 1 of a BigIntOpt instance. - bytes constant ONE = hex"0000000000000000000000000000000000000000000000000000000000000001"; - /// @notice the value for number 2 of a BigIntOpt instance. - bytes constant TWO = hex"0000000000000000000000000000000000000000000000000000000000000002"; - - // ***************** BEGIN EXPOSED MANAGEMENT FUNCTIONS ****************** - /** @notice verify a BN instance - * @dev checks if the BN is in the correct format. operations should only be carried out on - * verified BNs, so it is necessary to call this if your function takes an arbitrary BN - * as input. - * - * @param bn BigIntOpt instance - */ - function verify( - BigIntOpt memory bn - ) internal pure { - uint msword; - bytes memory val = bn.val; - assembly {msword := mload(add(val,0x20))} //get msword of result - if(msword==0) require(isZero(bn)); - else require((bn.val.length % 32 == 0) && (msword>>((bn.bitlen-1)%256)==1)); - } - - /** @notice initOptialize a BN instance - * @dev wrapper function for _initOpt. initOptializes from bytes value. - * Allows passing bitLength of value. This is NOT verified in the internal function. Only use where bitlen is - * explicitly known; otherwise use the other initOpt function. - * - * @param val BN value. may be of any size. - * @param neg neg whether the BN is +/- - * @param bitlen bit length of output. - * @return BigIntOpt instance - */ - function initOpt( - bytes memory val, - bool neg, - uint bitlen - ) internal view returns(BigIntOpt memory){ - return _initOpt(val, neg, bitlen); - } - - /** @notice initOptialize a BN instance - * @dev wrapper function for _initOpt. initOptializes from bytes value. - * - * @param val BN value. may be of any size. - * @param neg neg whether the BN is +/- - * @return BigIntOpt instance - */ - function initOpt( - bytes memory val, - bool neg - ) internal view returns(BigIntOpt memory){ - return _initOpt(val, neg, 0); - } - - /** @notice initOptialize a BN instance - * @dev wrapper function for _initOpt. initOptializes from uint value (converts to bytes); - * tf. resulting BN is in the range -2^256-1 ... 2^256-1. - * - * @param val uint value. - * @param neg neg whether the BN is +/- - * @return BigIntOpt instance - */ - function initOpt( - uint val, - bool neg - ) internal view returns(BigIntOpt memory){ - return _initOpt(abi.encodePacked(val), neg, 0); - } - // ***************** END EXPOSED MANAGEMENT FUNCTIONS ****************** - - function add( - BigIntOpt memory a, - BigIntOpt memory b, - BigIntOpt memory temp - ) internal pure { - if(a.bitlen==0 && b.bitlen==0) { - delete temp; - } - if(a.bitlen==0) { - temp.val = b.val; - temp.bitlen = b.bitlen; - temp.neg = b.neg; - } - if(b.bitlen==0) { - temp.val = a.val; - temp.bitlen = a.bitlen; - temp.neg = a.neg; - } - // bytes memory val; - // uint bitlen; - int compare = cmp(a,b,false); - - if(a.neg || b.neg){ - if(a.neg && b.neg){ - if(compare>=0) (temp.val, temp.bitlen) = _add(a.val,b.val,a.bitlen); - else (temp.val, temp.bitlen) = _add(b.val,a.val,b.bitlen); - temp.neg = true; - } - else { - if(compare==1){ - (temp.val, temp.bitlen) = _sub(a.val,b.val); - temp.neg = a.neg; - } - else if(compare==-1){ - (temp.val, temp.bitlen) = _sub(b.val,a.val); - temp.neg = !a.neg; - } - else delete temp;//one pos and one neg, and same value. - } - } - else{ - if(compare>=0){ // a>=b - (temp.val, temp.bitlen) = _add(a.val,b.val,a.bitlen); - } - else { - (temp.val, temp.bitlen) = _add(b.val,a.val,b.bitlen); - } - temp.neg = false; - } - } - // _multiplyScalarPartial+ 2,561,331 - // _multiplyScalarPartial- 2,932,032 - - // _multiplyScalarPartial+ 2,556,615 - // _multiplyScalarPartial- 2,932,032 - -// _multiplyScalarPartial+ 2,550,279 -// _multiplyScalarPartial- 2,932,032 - function sub( - BigIntOpt memory a, - BigIntOpt memory b, - BigIntOpt memory temp - ) internal pure { - if(a.bitlen==0 && b.bitlen==0) delete temp; - //bytes memory val; - int compare; - //uint bitlen; - compare = cmp(a,b,false); - if(a.neg || b.neg) { - if(a.neg && b.neg){ - if(compare == 1) { - (temp.val,temp.bitlen) = _sub(a.val,b.val); - temp.neg = true; - } - else if(compare == -1) { - - (temp.val, temp.bitlen) = _sub(b.val,a.val); - temp.neg = false; - } - else delete temp; - } - else { - if(compare >= 0) (temp.val, temp.bitlen) = _add(a.val,b.val,a.bitlen); - else (temp.val,temp.bitlen) = _add(b.val,a.val,b.bitlen); - - temp.neg = (a.neg) ? true : false; - } - } - else { - if(compare == 1) { - (temp.val,temp.bitlen) = _sub(a.val,b.val); - temp.neg = false; - } - else if(compare == -1) { - (temp.val,temp.bitlen) = _sub(b.val,a.val); - temp.neg = true; - } - else delete temp; - } - - // temp.val = val; - // temp.bitlen = (bitlen); - } - - function mul( - BigIntOpt memory a, - BigIntOpt memory b, - BigIntOpt memory temp - ) internal view { - BigIntOpt memory _temp1; - BigIntOpt memory _temp2; - BigIntOpt memory _temp3; - - add(a,b, _temp1); - _powModulus(_temp1, 2, _temp3); - modexp(_temp1, two(), _temp3, _temp1); // (a+b)^2 - - // no need to do subtraction part of the equation if a == b; if so, it has no effect on final result. - if(!eq(a,b)) { - sub(a,b, _temp2); - _powModulus(_temp2, 2, _temp3); - modexp(_temp2, two(), _temp3, _temp2); // (a-b)^2 - - sub(_temp1, _temp2, _temp1); - } - - _shrOpt(_temp1, 2); - - temp.val = _temp1.val; - temp.bitlen = _temp1.bitlen; - temp.neg = _temp1.neg; - } - - function mod( - BigIntOpt memory a, - BigIntOpt memory n, - BigIntOpt memory temp - ) internal view{ - modexp(a, one(), n, temp); - } - - function modmul( - BigIntOpt memory a, - BigIntOpt memory b, - BigIntOpt memory n, - BigIntOpt memory temp) internal view { - mul(a,b, temp); - mod(temp, n, temp); - } - - function modexp( - BigIntOpt memory a, - BigIntOpt memory e, - BigIntOpt memory n, - BigIntOpt memory temp - ) internal view { - //if exponent is negative, other method with this same name should be used. - //if modulus is negative or zero, we cannot perform the operation. - require( e.neg==false - && n.neg==false - && !isZero(n.val)); - - bytes memory _result = _modexp(a.val,e.val,n.val); - //get bitlen of result (TODO: optimise. we know bitlen is in the same byte as the modulus bitlen byte) - uint bitlen = bitLength(_result); - - // if result is 0, immediately return. - if(bitlen == 0) { - delete temp; - } - // if base is negative AND exponent is odd, base^exp is negative, and tf. result is negative; - // in that case we make the result positive by adding the modulus. - if(a.neg && isOdd(e)) { - add(BigIntOpt(_result, true, bitlen), n, temp); - } - else { - // in any other case we return the positive result. - temp.val = _result; - temp.bitlen = bitlen; - temp.neg = false; - } - } - - // ***************** END EXPOSED CORE CALCULATION FUNCTIONS ****************** - - // ***************** START EXPOSED HELPER FUNCTIONS ****************** - /** @notice BigIntOpt odd number check - * @dev isOdd: returns 1 if BigIntOpt value is an odd number and 0 otherwise. - * - * @param a BigIntOpt - * @return r Boolean result - */ - function isOdd( - BigIntOpt memory a - ) internal pure returns(bool r){ - assembly{ - let a_ptr := add(mload(a), mload(mload(a))) // go to least significant word - r := mod(mload(a_ptr),2) // mod it with 2 (returns 0 or 1) - } - } - - /** @notice BigIntOpt comparison - * @dev cmp: Compares BigIntOpts a and b. 'signed' parameter indiciates whether to consider the sign of the inputs. - * 'trigger' is used to decide this - - * if both negative, invert the result; - * if both positive (or signed==false), trigger has no effect; - * if differing signs, we return immediately based on input. - * returns -1 on ab. - * - * @param a BigIntOpt - * @param b BigIntOpt - * @param signed whether to consider sign of inputs - * @return int result - */ - function cmp( - BigIntOpt memory a, - BigIntOpt memory b, - bool signed - ) internal pure returns(int){ - int trigger = 1; - if(signed){ - if(a.neg && b.neg) trigger = -1; - else if(a.neg==false && b.neg==true) return 1; - else if(a.neg==true && b.neg==false) return -1; - } - - if(a.bitlen>b.bitlen) return trigger; // 1*trigger - if(b.bitlen>a.bitlen) return -1*trigger; - - uint a_ptr; - uint b_ptr; - uint a_word; - uint b_word; - - uint len = a.val.length; //bitlen is same so no need to check length. - - assembly{ - a_ptr := add(mload(a),0x20) - b_ptr := add(mload(b),0x20) - } - - for(uint i=0; ib_word) return trigger; // 1*trigger - if(b_word>a_word) return -1*trigger; - - } - - return 0; //same value. - } - - /** @notice BigIntOpt equality - * @dev eq: returns true if a==b. sign always considered. - * - * @param a BigIntOpt - * @param b BigIntOpt - * @return boolean result - */ - function eq( - BigIntOpt memory a, - BigIntOpt memory b - ) internal pure returns(bool){ - int result = cmp(a, b, true); - return (result==0) ? true : false; - } - - /** @notice BigIntOpt greater than - * @dev eq: returns true if a>b. sign always considered. - * - * @param a BigIntOpt - * @param b BigIntOpt - * @return boolean result - */ - function gt( - BigIntOpt memory a, - BigIntOpt memory b - ) internal pure returns(bool){ - int result = cmp(a, b, true); - return (result==1) ? true : false; - } - - /** @notice BigIntOpt greater than or equal to - * @dev eq: returns true if a>=b. sign always considered. - * - * @param a BigIntOpt - * @param b BigIntOpt - * @return boolean result - */ - function gte( - BigIntOpt memory a, - BigIntOpt memory b - ) internal pure returns(bool){ - int result = cmp(a, b, true); - return (result==1 || result==0) ? true : false; - } - - /** @notice BigIntOpt less than - * @dev eq: returns true if a= the bitlength of the value the result is always 0 - if(bits >= bn.bitlen) return BigIntOpt(ZERO,false,0); - - // set bitlen initOptially as we will be potentially modifying 'bits' - bn.bitlen = bn.bitlen-(bits); - - // handle shifts greater than 256: - // if bits is greater than 256 we can simply remove any trailing words, by altering the BN length. - // we also update 'bits' so that it is now in the range 0..256. - assembly { - if or(gt(bits, 0x100), eq(bits, 0x100)) { - length := sub(length, mul(div(bits, 0x100), 0x20)) - mstore(mload(bn), length) - bits := mod(bits, 0x100) - } - - // if bits is multiple of 8 (byte size), we can simply use identity precompile for cheap memcopy. - // otherwise we shift each word, starting at the least signifcant word, one-by-one using the mask technique. - // TODO it is possible to do this without the last two operations, see SHL identity copy. - let bn_val_ptr := mload(bn) - switch eq(mod(bits, 8), 0) - case 1 { - let bytes_shift := div(bits, 8) - let in := mload(bn) - let inlength := mload(in) - let insize := add(inlength, 0x20) - let out := add(in, bytes_shift) - let outsize := sub(insize, bytes_shift) - let success := staticcall(450, 0x4, in, insize, out, insize) - mstore8(add(out, 0x1f), 0) // maintain our BN layout following identity call: - mstore(in, inlength) // set current length byte to 0, and reset old length. - } - default { - let mask - let lsw - let mask_shift := sub(0x100, bits) - let lsw_ptr := add(bn_val_ptr, length) - for { let i := length } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) - switch eq(i,0x20) // if i==32: - case 1 { mask := 0 } // - handles lsword: no mask needed. - default { mask := mload(sub(lsw_ptr,0x20)) } // - else get mask (previous word) - lsw := shr(bits, mload(lsw_ptr)) // right shift current by bits - mask := shl(mask_shift, mask) // left shift next significant word by mask_shift - mstore(lsw_ptr, or(lsw,mask)) // store OR'd mask and shifted bits in-place - lsw_ptr := sub(lsw_ptr, 0x20) // point to next bits. - } - } - - // The following removes the leading word containing all zeroes in the result should it exist, - // as well as updating lengths and pointers as necessary. - let msw_ptr := add(bn_val_ptr,0x20) - switch eq(mload(msw_ptr), 0) - case 1 { - mstore(msw_ptr, sub(mload(bn_val_ptr), 0x20)) // store new length in new position - mstore(bn, msw_ptr) // update pointer from bn - } - default {} - } - - - return bn; - } - - function _shrOpt(BigIntOpt memory bn, uint bits) internal view { - uint length; - assembly { length := mload(mload(bn)) } - - // if bits is >= the bitlength of the value the result is always 0 - if(bits >= bn.bitlen) { - delete bn; - } - - // set bitlen initOptially as we will be potentially modifying 'bits' - bn.bitlen = bn.bitlen-(bits); - - // handle shifts greater than 256: - // if bits is greater than 256 we can simply remove any trailing words, by altering the BN length. - // we also update 'bits' so that it is now in the range 0..256. - assembly { - if or(gt(bits, 0x100), eq(bits, 0x100)) { - length := sub(length, mul(div(bits, 0x100), 0x20)) - mstore(mload(bn), length) - bits := mod(bits, 0x100) - } - - // if bits is multiple of 8 (byte size), we can simply use identity precompile for cheap memcopy. - // otherwise we shift each word, starting at the least signifcant word, one-by-one using the mask technique. - // TODO it is possible to do this without the last two operations, see SHL identity copy. - let bn_val_ptr := mload(bn) - switch eq(mod(bits, 8), 0) - case 1 { - let bytes_shift := div(bits, 8) - let in := mload(bn) - let inlength := mload(in) - let insize := add(inlength, 0x20) - let out := add(in, bytes_shift) - let outsize := sub(insize, bytes_shift) - let success := staticcall(450, 0x4, in, insize, out, insize) - mstore8(add(out, 0x1f), 0) // maintain our BN layout following identity call: - mstore(in, inlength) // set current length byte to 0, and reset old length. - } - default { - let mask - let lsw - let mask_shift := sub(0x100, bits) - let lsw_ptr := add(bn_val_ptr, length) - for { let i := length } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) - switch eq(i,0x20) // if i==32: - case 1 { mask := 0 } // - handles lsword: no mask needed. - default { mask := mload(sub(lsw_ptr,0x20)) } // - else get mask (previous word) - lsw := shr(bits, mload(lsw_ptr)) // right shift current by bits - mask := shl(mask_shift, mask) // left shift next significant word by mask_shift - mstore(lsw_ptr, or(lsw,mask)) // store OR'd mask and shifted bits in-place - lsw_ptr := sub(lsw_ptr, 0x20) // point to next bits. - } - } - - // The following removes the leading word containing all zeroes in the result should it exist, - // as well as updating lengths and pointers as necessary. - let msw_ptr := add(bn_val_ptr,0x20) - switch eq(mload(msw_ptr), 0) - case 1 { - mstore(msw_ptr, sub(mload(bn_val_ptr), 0x20)) // store new length in new position - mstore(bn, msw_ptr) // update pointer from bn - } - default {} - } - } - - /** @notice left shift BigIntOpt value - * @dev shr: left shift BigIntOpt a by 'bits' bits. - ensures the value is not negative before calling the private function. - * @param a BigIntOpt value to shift - * @param bits amount of bits to shift by - * @return result BigIntOpt - */ - function shl( - BigIntOpt memory a, - uint bits - ) internal view returns(BigIntOpt memory){ - require(!a.neg); - return _shl(a, bits); - } - - /** @notice sha3 hash a BigIntOpt. - * @dev hash: takes a BigIntOpt and performs sha3 hash on it. - * we hash each BigIntOpt WITHOUT it's first word - first word is a pointer to the start of the bytes value, - * and so is different for each struct. - * - * @param a BigIntOpt - * @return h bytes32 hash. - */ - function hash( - BigIntOpt memory a - ) internal pure returns(bytes32 h) { - //amount of words to hash = all words of the value and three extra words: neg, bitlen & value length. - assembly { - h := keccak256( add(a,0x20), add (mload(mload(a)), 0x60 ) ) - } - } - - /** @notice BigIntOpt full zero check - * @dev isZero: checks if the BigIntOpt is in the default zero format for BNs (ie. the result from zero()). - * - * @param a BigIntOpt - * @return boolean result. - */ - function isZero( - BigIntOpt memory a - ) internal pure returns(bool) { - return isZero(a.val) && a.val.length==0x20 && !a.neg && a.bitlen == 0; - } - - - /** @notice bytes zero check - * @dev isZero: checks if input bytes value resolves to zero. - * - * @param a bytes value - * @return boolean result. - */ - function isZero( - bytes memory a - ) internal pure returns(bool) { - uint msword; - uint msword_ptr; - assembly { - msword_ptr := add(a,0x20) - } - for(uint i=0; i 0) return false; - assembly { msword_ptr := add(msword_ptr, 0x20) } - } - return true; - - } - - /** @notice BigIntOpt value bit length - * @dev bitLength: returns BigIntOpt value bit length- ie. log2 (most significant bit of value) - * - * @param a BigIntOpt - * @return uint bit length result. - */ - function bitLength( - BigIntOpt memory a - ) internal pure returns(uint){ - return bitLength(a.val); - } - - /** @notice bytes bit length - * @dev bitLength: returns bytes bit length- ie. log2 (most significant bit of value) - * - * @param a bytes value - * @return r uint bit length result. - */ - function bitLength( - bytes memory a - ) internal pure returns(uint r){ - if(isZero(a)) return 0; - uint msword; - assembly { - msword := mload(add(a,0x20)) // get msword of input - } - r = bitLength(msword); // get bitlen of msword, add to size of remaining words. - assembly { - r := add(r, mul(sub(mload(a), 0x20) , 8)) // res += (val.length-32)*8; - } - } - - /** @notice uint bit length - @dev bitLength: get the bit length of a uint input - ie. log2 (most significant bit of 256 bit value (one EVM word)) - * credit: Tjaden Hess @ ethereum.stackexchange - * @param a uint value - * @return r uint bit length result. - */ - function bitLength( - uint a - ) internal pure returns (uint r){ - assembly { - switch eq(a, 0) - case 1 { - r := 0 - } - default { - let arg := a - a := sub(a,1) - a := or(a, div(a, 0x02)) - a := or(a, div(a, 0x04)) - a := or(a, div(a, 0x10)) - a := or(a, div(a, 0x100)) - a := or(a, div(a, 0x10000)) - a := or(a, div(a, 0x100000000)) - a := or(a, div(a, 0x10000000000000000)) - a := or(a, div(a, 0x100000000000000000000000000000000)) - a := add(a, 1) - let m := mload(0x40) - mstore(m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd) - mstore(add(m,0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe) - mstore(add(m,0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616) - mstore(add(m,0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff) - mstore(add(m,0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e) - mstore(add(m,0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707) - mstore(add(m,0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606) - mstore(add(m,0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100) - mstore(0x40, add(m, 0x100)) - let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff - let shift := 0x100000000000000000000000000000000000000000000000000000000000000 - let _a := div(mul(a, magic), shift) - r := div(mload(add(m,sub(255,_a))), shift) - r := add(r, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000))) - // where a is a power of two, result needs to be incremented. we use the power of two trick here: if(arg & arg-1 == 0) ++r; - if eq(and(arg, sub(arg, 1)), 0) { - r := add(r, 1) - } - } - } - } - - /** @notice BigIntOpt zero value - @dev zero: returns zero encoded as a BigIntOpt - * @return zero encoded as BigIntOpt - */ - function zero( - ) internal pure returns(BigIntOpt memory) { - return BigIntOpt(ZERO, false, 0); - } - - /** @notice BigIntOpt one value - @dev one: returns one encoded as a BigIntOpt - * @return one encoded as BigIntOpt - */ - function one( - ) internal pure returns(BigIntOpt memory) { - return BigIntOpt(ONE, false, 1); - } - - /** @notice BigIntOpt two value - @dev two: returns two encoded as a BigIntOpt - * @return two encoded as BigIntOpt - */ - function two( - ) internal pure returns(BigIntOpt memory) { - return BigIntOpt(TWO, false, 2); - } - // ***************** END EXPOSED HELPER FUNCTIONS ****************** - - - - - - // ***************** START PRIVATE MANAGEMENT FUNCTIONS ****************** - /** @notice Create a new BigIntOpt. - @dev initOpt: overloading allows caller to obtionally pass bitlen where it is known - as it is cheaper to do off-chain and verify on-chain. - * we assert input is in data structure as defined above, and that bitlen, if passed, is correct. - * 'copy' parameter indicates whether or not to copy the contents of val to a new location in memory (for example where you pass - * the contents of another variable's value in) - * @param val bytes - bignum value. - * @param neg bool - sign of value - * @param bitlen uint - bit length of value - * @return r BigIntOpt initOptialized value. - */ - function _initOpt( - bytes memory val, - bool neg, - uint bitlen - ) private view returns(BigIntOpt memory r){ - // use identity at location 0x4 for cheap memcpy. - // grab contents of val, load starting from memory end, update memory end pointer. - assembly { - let data := add(val, 0x20) - let length := mload(val) - let out - let freemem := mload(0x40) - switch eq(mod(length, 0x20), 0) // if(val.length % 32 == 0) - case 1 { - out := add(freemem, 0x20) // freememory location + length word - mstore(freemem, length) // set new length - } - default { - let offset := sub(0x20, mod(length, 0x20)) // offset: 32 - (length % 32) - out := add(add(freemem, offset), 0x20) // freememory location + offset + length word - mstore(freemem, add(length, offset)) // set new length - } - pop(staticcall(450, 0x4, data, length, out, length)) // copy into 'out' memory location - mstore(0x40, add(freemem, add(mload(freemem), 0x20))) // update the free memory pointer - - // handle leading zero words. assume freemem is pointer to bytes value - let bn_length := mload(freemem) - for { } eq ( eq(bn_length, 0x20), 0) { } { // for(; length!=32; length-=32) - switch eq(mload(add(freemem, 0x20)),0) // if(msword==0): - case 1 { freemem := add(freemem, 0x20) } // update length pointer - default { break } // else: loop termination. non-zero word found - bn_length := sub(bn_length,0x20) - } - mstore(freemem, bn_length) - - mstore(r, freemem) // store new bytes value in r - mstore(add(r, 0x20), neg) // store neg value in r - } - - r.bitlen = bitlen == 0 ? bitLength(r.val) : bitlen; - } - // ***************** END PRIVATE MANAGEMENT FUNCTIONS ****************** - - - - - - // ***************** START PRIVATE CORE CALCULATION FUNCTIONS ****************** - /** @notice takes two BigIntOpt memory values and the bitlen of the max value, and adds them. - * @dev _add: This function is private and only callable from add: therefore the values may be of different sizes, - * in any order of size, and of different signs (handled in add). - * As values may be of different sizes, inputs are considered starting from the least significant - * words, working back. - * The function calculates the new bitlen (basically if bitlens are the same for max and min, - * max_bitlen++) and returns a new BigIntOpt memory value. - * - * @param max bytes - biggest value (determined from add) - * @param min bytes - smallest value (determined from add) - * @param max_bitlen uint - bit length of max value. - * @return bytes result - max + min. - * @return uint - bit length of result. - */ - function _add( - bytes memory max, - bytes memory min, - uint max_bitlen - ) private pure returns (bytes memory, uint) { - bytes memory result; - assembly { - - let result_start := mload(0x40) // Get the highest available block of memory - let carry := 0 - let uint_max := sub(0,1) - - let max_ptr := add(max, mload(max)) - let min_ptr := add(min, mload(min)) // point to last word of each byte array. - - let result_ptr := add(add(result_start,0x20), mload(max)) // set result_ptr end. - - for { let i := mload(max) } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) - let max_val := mload(max_ptr) // get next word for 'max' - switch gt(i,sub(mload(max),mload(min))) // if(i>(max_length-min_length)). while - // 'min' words are still available. - case 1{ - let min_val := mload(min_ptr) // get next word for 'min' - mstore(result_ptr, add(add(max_val,min_val),carry)) // result_word = max_word+min_word+carry - switch gt(max_val, sub(uint_max,sub(min_val,carry))) // this switch block finds whether or - // not to set the carry bit for the - // next iteration. - case 1 { carry := 1 } - default { - switch and(eq(max_val,uint_max),or(gt(carry,0), gt(min_val,0))) - case 1 { carry := 1 } - default{ carry := 0 } - } - - min_ptr := sub(min_ptr,0x20) // point to next 'min' word - } - default{ // else: remainder after 'min' words are complete. - mstore(result_ptr, add(max_val,carry)) // result_word = max_word+carry - - switch and( eq(uint_max,max_val), eq(carry,1) ) // this switch block finds whether or - // not to set the carry bit for the - // next iteration. - case 1 { carry := 1 } - default { carry := 0 } - } - result_ptr := sub(result_ptr,0x20) // point to next 'result' word - max_ptr := sub(max_ptr,0x20) // point to next 'max' word - } - - switch eq(carry,0) - case 1{ result_start := add(result_start,0x20) } // if carry is 0, increment result_start, ie. - // length word for result is now one word - // position ahead. - default { mstore(result_ptr, 1) } // else if carry is 1, store 1; overflow has - // occured, so length word remains in the - // same position. - - result := result_start // point 'result' bytes value to the correct - // address in memory. - mstore(result,add(mload(max),mul(0x20,carry))) // store length of result. we are finished - // with the byte array. - - mstore(0x40, add(result,add(mload(result),0x20))) // Update freemem pointer to point to new - // end of memory. - - // we now calculate the result's bit length. - // with addition, if we assume that some a is at least equal to some b, then the resulting bit length will - // be a's bit length or (a's bit length)+1, depending on carry bit.this is cheaper than calling bitLength. - let msword := mload(add(result,0x20)) // get most significant word of result - // if(msword==1 || msword>>(max_bitlen % 256)==1): - if or( eq(msword, 1), eq(shr(mod(max_bitlen,256),msword),1) ) { - max_bitlen := add(max_bitlen, 1) // if msword's bit length is 1 greater - // than max_bitlen, OR overflow occured, - // new bitlen is max_bitlen+1. - } - } - - - return (result, max_bitlen); - } - - /** @notice takes two BigIntOpt memory values and subtracts them. - * @dev _sub: This function is private and only callable from add: therefore the values may be of different sizes, - * in any order of size, and of different signs (handled in add). - * As values may be of different sizes, inputs are considered starting from the least significant words, - * working back. - * The function calculates the new bitlen (basically if bitlens are the same for max and min, - * max_bitlen++) and returns a new BigIntOpt memory value. - * - * @param max bytes - biggest value (determined from add) - * @param min bytes - smallest value (determined from add) - * @return bytes result - max + min. - * @return uint - bit length of result. - */ - function _sub( - bytes memory max, - bytes memory min - ) internal pure returns (bytes memory, uint) { - bytes memory result; - uint carry = 0; - uint uint_max = type(uint256).max; - assembly { - - let result_start := mload(0x40) // Get the highest available block of - // memory - - let max_len := mload(max) - let min_len := mload(min) // load lengths of inputs - - let len_diff := sub(max_len,min_len) // get differences in lengths. - - let max_ptr := add(max, max_len) - let min_ptr := add(min, min_len) // go to end of arrays - let result_ptr := add(result_start, max_len) // point to least significant result - // word. - let memory_end := add(result_ptr,0x20) // save memory_end to update free memory - // pointer at the end. - - for { let i := max_len } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) - let max_val := mload(max_ptr) // get next word for 'max' - switch gt(i,len_diff) // if(i>(max_length-min_length)). while - // 'min' words are still available. - case 1{ - let min_val := mload(min_ptr) // get next word for 'min' - - mstore(result_ptr, sub(sub(max_val,min_val),carry)) // result_word = (max_word-min_word)-carry - - switch or(lt(max_val, add(min_val,carry)), - and(eq(min_val,uint_max), eq(carry,1))) // this switch block finds whether or - // not to set the carry bit for the next iteration. - case 1 { carry := 1 } - default { carry := 0 } - - min_ptr := sub(min_ptr,0x20) // point to next 'result' word - } - default { // else: remainder after 'min' words are complete. - - mstore(result_ptr, sub(max_val,carry)) // result_word = max_word-carry - - switch and( eq(max_val,0), eq(carry,1) ) // this switch block finds whether or - // not to set the carry bit for the - // next iteration. - case 1 { carry := 1 } - default { carry := 0 } - - } - result_ptr := sub(result_ptr,0x20) // point to next 'result' word - max_ptr := sub(max_ptr,0x20) // point to next 'max' word - } - - //the following code removes any leading words containing all zeroes in the result. - result_ptr := add(result_ptr,0x20) - - // for(result_ptr+=32;; result==0; result_ptr+=32) - for { } eq(mload(result_ptr), 0) { result_ptr := add(result_ptr,0x20) } { - result_start := add(result_start, 0x20) // push up the start pointer for the result - max_len := sub(max_len,0x20) // subtract a word (32 bytes) from the - // result length. - } - - result := result_start // point 'result' bytes value to - // the correct address in memory - - mstore(result,max_len) // store length of result. we - // are finished with the byte array. - - mstore(0x40, memory_end) // Update freemem pointer. - } - - uint new_bitlen = bitLength(result); // calculate the result's - // bit length. - - return (result, new_bitlen); - } - - function _powModulus( - BigIntOpt memory a, - uint e, - BigIntOpt memory temp - ) private pure{ - bytes memory _modulus = ZERO; - uint mod_index; - - assembly { - mod_index := mul(mload(add(a, 0x40)), e) // a.bitlen * e is the max bitlength of result - let first_word_modulus := shl(mod(mod_index, 256), 1) // set bit in first modulus word. - mstore(_modulus, mul(add(div(mod_index,256),1),0x20)) // store length of modulus - mstore(add(_modulus,0x20), first_word_modulus) // set first modulus word - mstore(0x40, add(_modulus, add(mload(_modulus),0x20))) // update freemem pointer to be modulus index - // + length - } - - //create modulus BigIntOpt memory for modexp function - temp.val = _modulus; - temp.neg = false; - temp.bitlen = mod_index; - } - - /** @notice Modular Exponentiation: Takes bytes values for base, exp, mod and calls precompile for (base^exp)%^mod - * @dev modexp: Wrapper for built-in modexp (contract 0x5) as described here: - * https://github.com/ethereum/EIPs/pull/198 - * - * @param _b bytes base - * @param _e bytes base_inverse - * @param _m bytes exponent - * @param r bytes result. - */ - function _modexp( - bytes memory _b, - bytes memory _e, - bytes memory _m - ) private view returns(bytes memory r) { - assembly { - let bl := mload(_b) - let el := mload(_e) - let ml := mload(_m) - - let freemem := mload(0x40) // Free memory pointer is always stored at 0x40 - - mstore(freemem, bl) // arg[0] = base.length @ +0 - - mstore(add(freemem,32), el) // arg[1] = exp.length @ +32 - - mstore(add(freemem,64), ml) // arg[2] = mod.length @ +64 - - // arg[3] = base.bits @ + 96 - // Use identity built-in (contract 0x4) as a cheap memcpy - let success := staticcall(450, 0x4, add(_b,32), bl, add(freemem,96), bl) - - // arg[4] = exp.bits @ +96+base.length - let size := add(96, bl) - success := staticcall(450, 0x4, add(_e,32), el, add(freemem,size), el) - - // arg[5] = mod.bits @ +96+base.length+exp.length - size := add(size,el) - success := staticcall(450, 0x4, add(_m,32), ml, add(freemem,size), ml) - - switch success case 0 { invalid() } //fail where we haven't enough gas to make the call - - // Total size of input = 96+base.length+exp.length+mod.length - size := add(size,ml) - // Invoke contract 0x5, put return value right after mod.length, @ +96 - success := staticcall(sub(gas(), 1350), 0x5, freemem, size, add(freemem, 0x60), ml) - - switch success case 0 { invalid() } //fail where we haven't enough gas to make the call - - let length := ml - let msword_ptr := add(freemem, 0x60) - - ///the following code removes any leading words containing all zeroes in the result. - for { } eq ( eq(length, 0x20), 0) { } { // for(; length!=32; length-=32) - switch eq(mload(msword_ptr),0) // if(msword==0): - case 1 { msword_ptr := add(msword_ptr, 0x20) } // update length pointer - default { break } // else: loop termination. non-zero word found - length := sub(length,0x20) - } - r := sub(msword_ptr,0x20) - mstore(r, length) - - // point to the location of the return value (length, bits) - //assuming mod length is multiple of 32, return value is already in the right format. - mstore(0x40, add(add(96, freemem),ml)) //deallocate freemem pointer - } - } - // ***************** END PRIVATE CORE CALCULATION FUNCTIONS ****************** - - - - - - // ***************** START PRIVATE HELPER FUNCTIONS ****************** - /** @notice left shift BigIntOpt memory 'dividend' by 'value' bits. - * @param bn value to shift - * @param bits amount of bits to shift by - * @return r result - */ - function _shl( - BigIntOpt memory bn, - uint bits - ) private view returns(BigIntOpt memory r) { - if(bits==0 || bn.bitlen==0) return bn; - - // we start by creating an empty bytes array of the size of the output, based on 'bits'. - // for that we must get the amount of extra words needed for the output. - uint length = bn.val.length; - // position of bitlen in most significnat word - uint bit_position = ((bn.bitlen-1) % 256) + 1; - // total extra words. we check if the bits remainder will add one more word. - uint extra_words = (bits / 256) + ( (bits % 256) >= (256 - bit_position) ? 1 : 0); - // length of output - uint total_length = length + (extra_words * 0x20); - - r.bitlen = bn.bitlen+(bits); - r.neg = bn.neg; - bits %= 256; - - - bytes memory bn_shift; - uint bn_shift_ptr; - // the following efficiently creates an empty byte array of size 'total_length' - assembly { - let freemem_ptr := mload(0x40) // get pointer to free memory - mstore(freemem_ptr, total_length) // store bytes length - let mem_end := add(freemem_ptr, total_length) // end of memory - mstore(mem_end, 0) // store 0 at memory end - bn_shift := freemem_ptr // set pointer to bytes - bn_shift_ptr := add(bn_shift, 0x20) // get bn_shift pointer - mstore(0x40, add(mem_end, 0x20)) // update freemem pointer - } - - // use identity for cheap copy if bits is multiple of 8. - if(bits % 8 == 0) { - // calculate the position of the first byte in the result. - uint bytes_pos = ((256-(((bn.bitlen-1)+bits) % 256))-1) / 8; - uint insize = (bn.bitlen / 8) + ((bn.bitlen % 8 != 0) ? 1 : 0); - assembly { - let in := add(add(mload(bn), 0x20), div(sub(256, bit_position), 8)) - let out := add(bn_shift_ptr, bytes_pos) - let success := staticcall(450, 0x4, in, insize, out, length) - } - r.val = bn_shift; - return r; - } - - - uint mask; - uint mask_shift = 0x100-bits; - uint msw; - uint msw_ptr; - - assembly { - msw_ptr := add(mload(bn), 0x20) - } - - // handle first word before loop if the shift adds any extra words. - // the loop would handle it if the bit shift doesn't wrap into the next word, - // so we check only for that condition. - if((bit_position+bits) > 256){ - assembly { - msw := mload(msw_ptr) - mstore(bn_shift_ptr, shr(mask_shift, msw)) - bn_shift_ptr := add(bn_shift_ptr, 0x20) - } - } - - // as a result of creating the empty array we just have to operate on the words in the original bn. - for(uint i=bn.val.length; i!=0; i-=0x20){ // for each word: - assembly { - msw := mload(msw_ptr) // get most significant word - switch eq(i,0x20) // if i==32: - case 1 { mask := 0 } // handles msword: no mask needed. - default { mask := mload(add(msw_ptr,0x20)) } // else get mask (next word) - msw := shl(bits, msw) // left shift current msw by 'bits' - mask := shr(mask_shift, mask) // right shift next significant word by mask_shift - mstore(bn_shift_ptr, or(msw,mask)) // store OR'd mask and shifted bits in-place - msw_ptr := add(msw_ptr, 0x20) - bn_shift_ptr := add(bn_shift_ptr, 0x20) - } - } - - r.val = bn_shift; - } - // ***************** END PRIVATE HELPER FUNCTIONS ****************** -} diff --git a/contracts/utils/BigNumbers.sol b/contracts/utils/BigNumbers.sol deleted file mode 100644 index 0e38c55..0000000 --- a/contracts/utils/BigNumbers.sol +++ /dev/null @@ -1,1309 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; -// -//// Definition here allows both the lib and inheriting contracts to use BigNumber directly. -// struct BigNumber { -// bytes val; -// bool neg; -// uint bitlen; -// } -// -///** -// * @notice BigNumbers library for Solidity. -// */ -//library BigNumbers { -// -// /// @notice the value for number 0 of a BigNumber instance. -// bytes constant ZERO = hex"0000000000000000000000000000000000000000000000000000000000000000"; -// /// @notice the value for number 1 of a BigNumber instance. -// bytes constant ONE = hex"0000000000000000000000000000000000000000000000000000000000000001"; -// /// @notice the value for number 2 of a BigNumber instance. -// bytes constant TWO = hex"0000000000000000000000000000000000000000000000000000000000000002"; -// -// // ***************** BEGIN EXPOSED MANAGEMENT FUNCTIONS ****************** -// /** @notice verify a BN instance -// * @dev checks if the BN is in the correct format. operations should only be carried out on -// * verified BNs, so it is necessary to call this if your function takes an arbitrary BN -// * as input. -// * -// * @param bn BigNumber instance -// */ -// function verify( -// BigNumber memory bn -// ) public pure { -// uint msword; -// bytes memory val = bn.val; -// assembly {msword := mload(add(val,0x20))} //get msword of result -// if(msword==0) require(isZero(bn)); -// else require((bn.val.length % 32 == 0) && (msword>>((bn.bitlen-1)%256)==1)); -// } -// -// /** @notice initialize a BN instance -// * @dev wrapper function for _init. initializes from bytes value. -// * Allows passing bitLength of value. This is NOT verified in the public function. Only use where bitlen is -// * explicitly known; otherwise use the other init function. -// * -// * @param val BN value. may be of any size. -// * @param neg neg whether the BN is +/- -// * @param bitlen bit length of output. -// * @return BigNumber instance -// */ -// function init( -// bytes memory val, -// bool neg, -// uint bitlen -// ) public view returns(BigNumber memory){ -// return _init(val, neg, bitlen); -// } -// -// /** @notice initialize a BN instance -// * @dev wrapper function for _init. initializes from bytes value. -// * -// * @param val BN value. may be of any size. -// * @param neg neg whether the BN is +/- -// * @return BigNumber instance -// */ -// function init( -// bytes memory val, -// bool neg -// ) public view returns(BigNumber memory){ -// return _init(val, neg, 0); -// } -// -// /** @notice initialize a BN instance -// * @dev wrapper function for _init. initializes from uint value (converts to bytes); -// * tf. resulting BN is in the range -2^256-1 ... 2^256-1. -// * -// * @param val uint value. -// * @param neg neg whether the BN is +/- -// * @return BigNumber instance -// */ -// function init( -// uint val, -// bool neg -// ) public view returns(BigNumber memory){ -// return _init(abi.encodePacked(val), neg, 0); -// } -// // ***************** END EXPOSED MANAGEMENT FUNCTIONS ****************** -// -// -// -// -// // ***************** BEGIN EXPOSED CORE CALCULATION FUNCTIONS ****************** -// /** @notice BigNumber addition: a + b. -// * @dev add: Initially prepare BigNumbers for addition operation; internally calls actual addition/subtraction, -// * depending on inputs. -// * In order to do correct addition or subtraction we have to handle the sign. -// * This function discovers the sign of the result based on the inputs, and calls the correct operation. -// * -// * @param a first BN -// * @param b second BN -// * @return r result - addition of a and b. -// */ -// function add( -// BigNumber memory a, -// BigNumber memory b -// ) public pure returns(BigNumber memory r) { -// if(a.bitlen==0 && b.bitlen==0) return zero(); -// if(a.bitlen==0) return b; -// if(b.bitlen==0) return a; -// bytes memory val; -// uint bitlen; -// int compare = cmp(a,b,false); -// -// if(a.neg || b.neg){ -// if(a.neg && b.neg){ -// if(compare>=0) (val, bitlen) = _add(a.val,b.val,a.bitlen); -// else (val, bitlen) = _add(b.val,a.val,b.bitlen); -// r.neg = true; -// } -// else { -// if(compare==1){ -// (val, bitlen) = _sub(a.val,b.val); -// r.neg = a.neg; -// } -// else if(compare==-1){ -// (val, bitlen) = _sub(b.val,a.val); -// r.neg = !a.neg; -// } -// else return zero();//one pos and one neg, and same value. -// } -// } -// else{ -// if(compare>=0){ // a>=b -// (val, bitlen) = _add(a.val,b.val,a.bitlen); -// } -// else { -// (val, bitlen) = _add(b.val,a.val,b.bitlen); -// } -// r.neg = false; -// } -// -// r.val = val; -// r.bitlen = (bitlen); -// } -// -// /** @notice BigNumber subtraction: a - b. -// * @dev sub: Initially prepare BigNumbers for subtraction operation; internally calls actual addition/subtraction, -// depending on inputs. -// * In order to do correct addition or subtraction we have to handle the sign. -// * This function discovers the sign of the result based on the inputs, and calls the correct operation. -// * -// * @param a first BN -// * @param b second BN -// * @return r result - subtraction of a and b. -// */ -// function sub( -// BigNumber memory a, -// BigNumber memory b -// ) public pure returns(BigNumber memory r) { -// if(a.bitlen==0 && b.bitlen==0) return zero(); -// bytes memory val; -// int compare; -// uint bitlen; -// compare = cmp(a,b,false); -// if(a.neg || b.neg) { -// if(a.neg && b.neg){ -// if(compare == 1) { -// (val,bitlen) = _sub(a.val,b.val); -// r.neg = true; -// } -// else if(compare == -1) { -// -// (val,bitlen) = _sub(b.val,a.val); -// r.neg = false; -// } -// else return zero(); -// } -// else { -// if(compare >= 0) (val,bitlen) = _add(a.val,b.val,a.bitlen); -// else (val,bitlen) = _add(b.val,a.val,b.bitlen); -// -// r.neg = (a.neg) ? true : false; -// } -// } -// else { -// if(compare == 1) { -// (val,bitlen) = _sub(a.val,b.val); -// r.neg = false; -// } -// else if(compare == -1) { -// (val,bitlen) = _sub(b.val,a.val); -// r.neg = true; -// } -// else return zero(); -// } -// -// r.val = val; -// r.bitlen = (bitlen); -// } -// -// /** @notice BigNumber multiplication: a * b. -// * @dev mul: takes two BigNumbers and multiplys them. Order is irrelevant. -// * multiplication achieved using modexp precompile: -// * (a * b) = ((a + b)**2 - (a - b)**2) / 4 -// * -// * @param a first BN -// * @param b second BN -// * @return r result - multiplication of a and b. -// */ -// function mul( -// BigNumber memory a, -// BigNumber memory b -// ) public view returns(BigNumber memory r){ -// -// BigNumber memory lhs = add(a,b); -// BigNumber memory fst = modexp(lhs, two(), _powModulus(lhs, 2)); // (a+b)^2 -// -// // no need to do subtraction part of the equation if a == b; if so, it has no effect on final result. -// if(!eq(a,b)) { -// BigNumber memory rhs = sub(a,b); -// BigNumber memory snd = modexp(rhs, two(), _powModulus(rhs, 2)); // (a-b)^2 -// r = _shr(sub(fst, snd) , 2); // (a * b) = (((a + b)**2 - (a - b)**2) / 4 -// } -// else { -// r = _shr(fst, 2); // a==b ? (((a + b)**2 / 4 -// } -// } -// -// /** @notice BigNumber division verification: a * b. -// * @dev div: takes three BigNumbers (a,b and result), and verifies that a/b == result. -// * Performing BigNumber division on-chain is a significantly expensive operation. As a result, -// * we expose the ability to verify the result of a division operation, which is a constant time operation. -// * (a/b = result) == (a = b * result) -// * Integer division only; therefore: -// * verify ((b*result) + (a % (b*result))) == a. -// * eg. 17/7 == 2: -// * verify (7*2) + (17 % (7*2)) == 17. -// * The function returns a bool on successful verification. The require statements will ensure that false can never -// * be returned, however inheriting contracts may also want to put this function inside a require statement. -// * -// * @param a first BigNumber -// * @param b second BigNumber -// * @param r result BigNumber -// * @return bool whether or not the operation was verified -// */ -// function divVerify( -// BigNumber memory a, -// BigNumber memory b, -// BigNumber memory r -// ) public view returns(bool) { -// -// // first do zero check. -// // if ab. -// * -// * @param a BigNumber -// * @param b BigNumber -// * @param signed whether to consider sign of inputs -// * @return int result -// */ -// function cmp( -// BigNumber memory a, -// BigNumber memory b, -// bool signed -// ) public pure returns(int){ -// int trigger = 1; -// if(signed){ -// if(a.neg && b.neg) trigger = -1; -// else if(a.neg==false && b.neg==true) return 1; -// else if(a.neg==true && b.neg==false) return -1; -// } -// -// if(a.bitlen>b.bitlen) return trigger; // 1*trigger -// if(b.bitlen>a.bitlen) return -1*trigger; -// -// uint a_ptr; -// uint b_ptr; -// uint a_word; -// uint b_word; -// -// uint len = a.val.length; //bitlen is same so no need to check length. -// -// assembly{ -// a_ptr := add(mload(a),0x20) -// b_ptr := add(mload(b),0x20) -// } -// -// for(uint i=0; ib_word) return trigger; // 1*trigger -// if(b_word>a_word) return -1*trigger; -// -// } -// -// return 0; //same value. -// } -// -// /** @notice BigNumber equality -// * @dev eq: returns true if a==b. sign always considered. -// * -// * @param a BigNumber -// * @param b BigNumber -// * @return boolean result -// */ -// function eq( -// BigNumber memory a, -// BigNumber memory b -// ) public pure returns(bool){ -// int result = cmp(a, b, true); -// return (result==0) ? true : false; -// } -// -// /** @notice BigNumber greater than -// * @dev eq: returns true if a>b. sign always considered. -// * -// * @param a BigNumber -// * @param b BigNumber -// * @return boolean result -// */ -// function gt( -// BigNumber memory a, -// BigNumber memory b -// ) public pure returns(bool){ -// int result = cmp(a, b, true); -// return (result==1) ? true : false; -// } -// -// /** @notice BigNumber greater than or equal to -// * @dev eq: returns true if a>=b. sign always considered. -// * -// * @param a BigNumber -// * @param b BigNumber -// * @return boolean result -// */ -// function gte( -// BigNumber memory a, -// BigNumber memory b -// ) public pure returns(bool){ -// int result = cmp(a, b, true); -// return (result==1 || result==0) ? true : false; -// } -// -// /** @notice BigNumber less than -// * @dev eq: returns true if a= the bitlength of the value the result is always 0 -// if(bits >= bn.bitlen) return BigNumber(ZERO,false,0); -// -// // set bitlen initially as we will be potentially modifying 'bits' -// bn.bitlen = bn.bitlen-(bits); -// -// // handle shifts greater than 256: -// // if bits is greater than 256 we can simply remove any trailing words, by altering the BN length. -// // we also update 'bits' so that it is now in the range 0..256. -// assembly { -// if or(gt(bits, 0x100), eq(bits, 0x100)) { -// length := sub(length, mul(div(bits, 0x100), 0x20)) -// mstore(mload(bn), length) -// bits := mod(bits, 0x100) -// } -// -// // if bits is multiple of 8 (byte size), we can simply use identity precompile for cheap memcopy. -// // otherwise we shift each word, starting at the least signifcant word, one-by-one using the mask technique. -// // TODO it is possible to do this without the last two operations, see SHL identity copy. -// let bn_val_ptr := mload(bn) -// switch eq(mod(bits, 8), 0) -// case 1 { -// let bytes_shift := div(bits, 8) -// let in := mload(bn) -// let inlength := mload(in) -// let insize := add(inlength, 0x20) -// let out := add(in, bytes_shift) -// let outsize := sub(insize, bytes_shift) -// let success := staticcall(450, 0x4, in, insize, out, insize) -// mstore8(add(out, 0x1f), 0) // maintain our BN layout following identity call: -// mstore(in, inlength) // set current length byte to 0, and reset old length. -// } -// default { -// let mask -// let lsw -// let mask_shift := sub(0x100, bits) -// let lsw_ptr := add(bn_val_ptr, length) -// for { let i := length } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) -// switch eq(i,0x20) // if i==32: -// case 1 { mask := 0 } // - handles lsword: no mask needed. -// default { mask := mload(sub(lsw_ptr,0x20)) } // - else get mask (previous word) -// lsw := shr(bits, mload(lsw_ptr)) // right shift current by bits -// mask := shl(mask_shift, mask) // left shift next significant word by mask_shift -// mstore(lsw_ptr, or(lsw,mask)) // store OR'd mask and shifted bits in-place -// lsw_ptr := sub(lsw_ptr, 0x20) // point to next bits. -// } -// } -// -// // The following removes the leading word containing all zeroes in the result should it exist, -// // as well as updating lengths and pointers as necessary. -// let msw_ptr := add(bn_val_ptr,0x20) -// switch eq(mload(msw_ptr), 0) -// case 1 { -// mstore(msw_ptr, sub(mload(bn_val_ptr), 0x20)) // store new length in new position -// mstore(bn, msw_ptr) // update pointer from bn -// } -// default {} -// } -// -// -// return bn; -// } -// -// /** @notice left shift BigNumber value -// * @dev shr: left shift BigNumber a by 'bits' bits. -// ensures the value is not negative before calling the private function. -// * @param a BigNumber value to shift -// * @param bits amount of bits to shift by -// * @return result BigNumber -// */ -// function shl( -// BigNumber memory a, -// uint bits -// ) public view returns(BigNumber memory){ -// require(!a.neg); -// return _shl(a, bits); -// } -// -// /** @notice sha3 hash a BigNumber. -// * @dev hash: takes a BigNumber and performs sha3 hash on it. -// * we hash each BigNumber WITHOUT it's first word - first word is a pointer to the start of the bytes value, -// * and so is different for each struct. -// * -// * @param a BigNumber -// * @return h bytes32 hash. -// */ -// function hash( -// BigNumber memory a -// ) public pure returns(bytes32 h) { -// //amount of words to hash = all words of the value and three extra words: neg, bitlen & value length. -// assembly { -// h := keccak256( add(a,0x20), add (mload(mload(a)), 0x60 ) ) -// } -// } -// -// /** @notice BigNumber full zero check -// * @dev isZero: checks if the BigNumber is in the default zero format for BNs (ie. the result from zero()). -// * -// * @param a BigNumber -// * @return boolean result. -// */ -// function isZero( -// BigNumber memory a -// ) public pure returns(bool) { -// return isZero(a.val) && a.val.length==0x20 && !a.neg && a.bitlen == 0; -// } -// -// -// /** @notice bytes zero check -// * @dev isZero: checks if input bytes value resolves to zero. -// * -// * @param a bytes value -// * @return boolean result. -// */ -// function isZero( -// bytes memory a -// ) public pure returns(bool) { -// uint msword; -// uint msword_ptr; -// assembly { -// msword_ptr := add(a,0x20) -// } -// for(uint i=0; i 0) return false; -// assembly { msword_ptr := add(msword_ptr, 0x20) } -// } -// return true; -// -// } -// -// /** @notice BigNumber value bit length -// * @dev bitLength: returns BigNumber value bit length- ie. log2 (most significant bit of value) -// * -// * @param a BigNumber -// * @return uint bit length result. -// */ -// function bitLength( -// BigNumber memory a -// ) public pure returns(uint){ -// return bitLength(a.val); -// } -// -// /** @notice bytes bit length -// * @dev bitLength: returns bytes bit length- ie. log2 (most significant bit of value) -// * -// * @param a bytes value -// * @return r uint bit length result. -// */ -// function bitLength( -// bytes memory a -// ) public pure returns(uint r){ -// if(isZero(a)) return 0; -// uint msword; -// assembly { -// msword := mload(add(a,0x20)) // get msword of input -// } -// r = bitLength(msword); // get bitlen of msword, add to size of remaining words. -// assembly { -// r := add(r, mul(sub(mload(a), 0x20) , 8)) // res += (val.length-32)*8; -// } -// } -// -// /** @notice uint bit length -// @dev bitLength: get the bit length of a uint input - ie. log2 (most significant bit of 256 bit value (one EVM word)) -// * credit: Tjaden Hess @ ethereum.stackexchange -// * @param a uint value -// * @return r uint bit length result. -// */ -// function bitLength( -// uint a -// ) public pure returns (uint r){ -// assembly { -// switch eq(a, 0) -// case 1 { -// r := 0 -// } -// default { -// let arg := a -// a := sub(a,1) -// a := or(a, div(a, 0x02)) -// a := or(a, div(a, 0x04)) -// a := or(a, div(a, 0x10)) -// a := or(a, div(a, 0x100)) -// a := or(a, div(a, 0x10000)) -// a := or(a, div(a, 0x100000000)) -// a := or(a, div(a, 0x10000000000000000)) -// a := or(a, div(a, 0x100000000000000000000000000000000)) -// a := add(a, 1) -// let m := mload(0x40) -// mstore(m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd) -// mstore(add(m,0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe) -// mstore(add(m,0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616) -// mstore(add(m,0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff) -// mstore(add(m,0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e) -// mstore(add(m,0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707) -// mstore(add(m,0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606) -// mstore(add(m,0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100) -// mstore(0x40, add(m, 0x100)) -// let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff -// let shift := 0x100000000000000000000000000000000000000000000000000000000000000 -// let _a := div(mul(a, magic), shift) -// r := div(mload(add(m,sub(255,_a))), shift) -// r := add(r, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000))) -// // where a is a power of two, result needs to be incremented. we use the power of two trick here: if(arg & arg-1 == 0) ++r; -// if eq(and(arg, sub(arg, 1)), 0) { -// r := add(r, 1) -// } -// } -// } -// } -// -// /** @notice BigNumber zero value -// @dev zero: returns zero encoded as a BigNumber -// * @return zero encoded as BigNumber -// */ -// function zero( -// ) public pure returns(BigNumber memory) { -// return BigNumber(ZERO, false, 0); -// } -// -// /** @notice BigNumber one value -// @dev one: returns one encoded as a BigNumber -// * @return one encoded as BigNumber -// */ -// function one( -// ) public pure returns(BigNumber memory) { -// return BigNumber(ONE, false, 1); -// } -// -// /** @notice BigNumber two value -// @dev two: returns two encoded as a BigNumber -// * @return two encoded as BigNumber -// */ -// function two( -// ) public pure returns(BigNumber memory) { -// return BigNumber(TWO, false, 2); -// } -// // ***************** END EXPOSED HELPER FUNCTIONS ****************** -// -// -// -// -// -// // ***************** START PRIVATE MANAGEMENT FUNCTIONS ****************** -// /** @notice Create a new BigNumber. -// @dev init: overloading allows caller to obtionally pass bitlen where it is known - as it is cheaper to do off-chain and verify on-chain. -// * we assert input is in data structure as defined above, and that bitlen, if passed, is correct. -// * 'copy' parameter indicates whether or not to copy the contents of val to a new location in memory (for example where you pass -// * the contents of another variable's value in) -// * @param val bytes - bignum value. -// * @param neg bool - sign of value -// * @param bitlen uint - bit length of value -// * @return r BigNumber initialized value. -// */ -// function _init( -// bytes memory val, -// bool neg, -// uint bitlen -// ) private view returns(BigNumber memory r){ -// // use identity at location 0x4 for cheap memcpy. -// // grab contents of val, load starting from memory end, update memory end pointer. -// assembly { -// let data := add(val, 0x20) -// let length := mload(val) -// let out -// let freemem := mload(0x40) -// switch eq(mod(length, 0x20), 0) // if(val.length % 32 == 0) -// case 1 { -// out := add(freemem, 0x20) // freememory location + length word -// mstore(freemem, length) // set new length -// } -// default { -// let offset := sub(0x20, mod(length, 0x20)) // offset: 32 - (length % 32) -// out := add(add(freemem, offset), 0x20) // freememory location + offset + length word -// mstore(freemem, add(length, offset)) // set new length -// } -// pop(staticcall(450, 0x4, data, length, out, length)) // copy into 'out' memory location -// mstore(0x40, add(freemem, add(mload(freemem), 0x20))) // update the free memory pointer -// -// // handle leading zero words. assume freemem is pointer to bytes value -// let bn_length := mload(freemem) -// for { } eq ( eq(bn_length, 0x20), 0) { } { // for(; length!=32; length-=32) -// switch eq(mload(add(freemem, 0x20)),0) // if(msword==0): -// case 1 { freemem := add(freemem, 0x20) } // update length pointer -// default { break } // else: loop termination. non-zero word found -// bn_length := sub(bn_length,0x20) -// } -// mstore(freemem, bn_length) -// -// mstore(r, freemem) // store new bytes value in r -// mstore(add(r, 0x20), neg) // store neg value in r -// } -// -// r.bitlen = bitlen == 0 ? bitLength(r.val) : bitlen; -// } -// // ***************** END PRIVATE MANAGEMENT FUNCTIONS ****************** -// -// -// -// -// -// // ***************** START PRIVATE CORE CALCULATION FUNCTIONS ****************** -// /** @notice takes two BigNumber memory values and the bitlen of the max value, and adds them. -// * @dev _add: This function is private and only callable from add: therefore the values may be of different sizes, -// * in any order of size, and of different signs (handled in add). -// * As values may be of different sizes, inputs are considered starting from the least significant -// * words, working back. -// * The function calculates the new bitlen (basically if bitlens are the same for max and min, -// * max_bitlen++) and returns a new BigNumber memory value. -// * -// * @param max bytes - biggest value (determined from add) -// * @param min bytes - smallest value (determined from add) -// * @param max_bitlen uint - bit length of max value. -// * @return bytes result - max + min. -// * @return uint - bit length of result. -// */ -// function _add( -// bytes memory max, -// bytes memory min, -// uint max_bitlen -// ) private pure returns (bytes memory, uint) { -// bytes memory result; -// assembly { -// -// let result_start := mload(0x40) // Get the highest available block of memory -// let carry := 0 -// let uint_max := sub(0,1) -// -// let max_ptr := add(max, mload(max)) -// let min_ptr := add(min, mload(min)) // point to last word of each byte array. -// -// let result_ptr := add(add(result_start,0x20), mload(max)) // set result_ptr end. -// -// for { let i := mload(max) } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) -// let max_val := mload(max_ptr) // get next word for 'max' -// switch gt(i,sub(mload(max),mload(min))) // if(i>(max_length-min_length)). while -// // 'min' words are still available. -// case 1{ -// let min_val := mload(min_ptr) // get next word for 'min' -// mstore(result_ptr, add(add(max_val,min_val),carry)) // result_word = max_word+min_word+carry -// switch gt(max_val, sub(uint_max,sub(min_val,carry))) // this switch block finds whether or -// // not to set the carry bit for the -// // next iteration. -// case 1 { carry := 1 } -// default { -// switch and(eq(max_val,uint_max),or(gt(carry,0), gt(min_val,0))) -// case 1 { carry := 1 } -// default{ carry := 0 } -// } -// -// min_ptr := sub(min_ptr,0x20) // point to next 'min' word -// } -// default{ // else: remainder after 'min' words are complete. -// mstore(result_ptr, add(max_val,carry)) // result_word = max_word+carry -// -// switch and( eq(uint_max,max_val), eq(carry,1) ) // this switch block finds whether or -// // not to set the carry bit for the -// // next iteration. -// case 1 { carry := 1 } -// default { carry := 0 } -// } -// result_ptr := sub(result_ptr,0x20) // point to next 'result' word -// max_ptr := sub(max_ptr,0x20) // point to next 'max' word -// } -// -// switch eq(carry,0) -// case 1{ result_start := add(result_start,0x20) } // if carry is 0, increment result_start, ie. -// // length word for result is now one word -// // position ahead. -// default { mstore(result_ptr, 1) } // else if carry is 1, store 1; overflow has -// // occured, so length word remains in the -// // same position. -// -// result := result_start // point 'result' bytes value to the correct -// // address in memory. -// mstore(result,add(mload(max),mul(0x20,carry))) // store length of result. we are finished -// // with the byte array. -// -// mstore(0x40, add(result,add(mload(result),0x20))) // Update freemem pointer to point to new -// // end of memory. -// -// // we now calculate the result's bit length. -// // with addition, if we assume that some a is at least equal to some b, then the resulting bit length will -// // be a's bit length or (a's bit length)+1, depending on carry bit.this is cheaper than calling bitLength. -// let msword := mload(add(result,0x20)) // get most significant word of result -// // if(msword==1 || msword>>(max_bitlen % 256)==1): -// if or( eq(msword, 1), eq(shr(mod(max_bitlen,256),msword),1) ) { -// max_bitlen := add(max_bitlen, 1) // if msword's bit length is 1 greater -// // than max_bitlen, OR overflow occured, -// // new bitlen is max_bitlen+1. -// } -// } -// -// -// return (result, max_bitlen); -// } -// -// /** @notice takes two BigNumber memory values and subtracts them. -// * @dev _sub: This function is private and only callable from add: therefore the values may be of different sizes, -// * in any order of size, and of different signs (handled in add). -// * As values may be of different sizes, inputs are considered starting from the least significant words, -// * working back. -// * The function calculates the new bitlen (basically if bitlens are the same for max and min, -// * max_bitlen++) and returns a new BigNumber memory value. -// * -// * @param max bytes - biggest value (determined from add) -// * @param min bytes - smallest value (determined from add) -// * @return bytes result - max + min. -// * @return uint - bit length of result. -// */ -// function _sub( -// bytes memory max, -// bytes memory min -// ) public pure returns (bytes memory, uint) { -// bytes memory result; -// uint carry = 0; -// uint uint_max = type(uint256).max; -// assembly { -// -// let result_start := mload(0x40) // Get the highest available block of -// // memory -// -// let max_len := mload(max) -// let min_len := mload(min) // load lengths of inputs -// -// let len_diff := sub(max_len,min_len) // get differences in lengths. -// -// let max_ptr := add(max, max_len) -// let min_ptr := add(min, min_len) // go to end of arrays -// let result_ptr := add(result_start, max_len) // point to least significant result -// // word. -// let memory_end := add(result_ptr,0x20) // save memory_end to update free memory -// // pointer at the end. -// -// for { let i := max_len } eq(eq(i,0),0) { i := sub(i, 0x20) } { // for(int i=max_length; i!=0; i-=32) -// let max_val := mload(max_ptr) // get next word for 'max' -// switch gt(i,len_diff) // if(i>(max_length-min_length)). while -// // 'min' words are still available. -// case 1{ -// let min_val := mload(min_ptr) // get next word for 'min' -// -// mstore(result_ptr, sub(sub(max_val,min_val),carry)) // result_word = (max_word-min_word)-carry -// /// max_val < min_val + carry || (min_val == uint256_max) && carry == 1 -// switch or(lt(max_val, add(min_val,carry)), -// and(eq(min_val,uint_max), eq(carry,1))) // this switch block finds whether or -// // not to set the carry bit for the next iteration. -// case 1 { carry := 1 } -// default { carry := 0 } -// -// min_ptr := sub(min_ptr,0x20) // point to next 'result' word -// } -// default { // else: remainder after 'min' words are complete. -// -// mstore(result_ptr, sub(max_val,carry)) // result_word = max_word-carry -// -// switch and( eq(max_val,0), eq(carry,1) ) // this switch block finds whether or -// // not to set the carry bit for the -// // next iteration. -// case 1 { carry := 1 } -// default { carry := 0 } -// -// } -// result_ptr := sub(result_ptr,0x20) // point to next 'result' word -// max_ptr := sub(max_ptr,0x20) // point to next 'max' word -// } -// -// //the following code removes any leading words containing all zeroes in the result. -// result_ptr := add(result_ptr,0x20) -// -// // for(result_ptr+=32;; result==0; result_ptr+=32) -// for { } eq(mload(result_ptr), 0) { result_ptr := add(result_ptr,0x20) } { -// result_start := add(result_start, 0x20) // push up the start pointer for the result -// max_len := sub(max_len,0x20) // subtract a word (32 bytes) from the -// // result length. -// } -// -// result := result_start // point 'result' bytes value to -// // the correct address in memory -// -// mstore(result,max_len) // store length of result. we -// // are finished with the byte array. -// -// mstore(0x40, memory_end) // Update freemem pointer. -// } -// -// uint new_bitlen = bitLength(result); // calculate the result's -// // bit length. -// -// return (result, new_bitlen); -// } -// -// /** @notice gets the modulus value necessary for calculating exponetiation. -// * @dev _powModulus: we must pass the minimum modulus value which would return JUST the a^b part of the calculation -// * in modexp. the rationale here is: -// * if 'a' has n bits, then a^e has at most n*e bits. -// * using this modulus in exponetiation will result in simply a^e. -// * therefore the value may be many words long. -// * This is done by: -// * - storing total modulus byte length -// * - storing first word of modulus with correct bit set -// * - updating the free memory pointer to come after total length. -// * -// * @param a BigNumber base -// * @param e uint exponent -// * @return BigNumber modulus result -// */ -// function _powModulus( -// BigNumber memory a, -// uint e -// ) private pure returns(BigNumber memory){ -// bytes memory _modulus = ZERO; -// uint mod_index; -// -// assembly { -// mod_index := mul(mload(add(a, 0x40)), e) // a.bitlen * e is the max bitlength of result -// let first_word_modulus := shl(mod(mod_index, 256), 1) // set bit in first modulus word. -// mstore(_modulus, mul(add(div(mod_index,256),1),0x20)) // store length of modulus -// mstore(add(_modulus,0x20), first_word_modulus) // set first modulus word -// mstore(0x40, add(_modulus, add(mload(_modulus),0x20))) // update freemem pointer to be modulus index -// // + length -// } -// -// //create modulus BigNumber memory for modexp function -// return BigNumber(_modulus, false, mod_index); -// } -// -// /** @notice Modular Exponentiation: Takes bytes values for base, exp, mod and calls precompile for (base^exp)%^mod -// * @dev modexp: Wrapper for built-in modexp (contract 0x5) as described here: -// * https://github.com/ethereum/EIPs/pull/198 -// * -// * @param _b bytes base -// * @param _e bytes base_inverse -// * @param _m bytes exponent -// * @param r bytes result. -// */ -// function _modexp( -// bytes memory _b, -// bytes memory _e, -// bytes memory _m -// ) private view returns(bytes memory r) { -// assembly { -// -// let bl := mload(_b) -// let el := mload(_e) -// let ml := mload(_m) -// -// -// let freemem := mload(0x40) // Free memory pointer is always stored at 0x40 -// -// -// mstore(freemem, bl) // arg[0] = base.length @ +0 -// -// mstore(add(freemem,32), el) // arg[1] = exp.length @ +32 -// -// mstore(add(freemem,64), ml) // arg[2] = mod.length @ +64 -// -// // arg[3] = base.bits @ + 96 -// // Use identity built-in (contract 0x4) as a cheap memcpy -// let success := staticcall(450, 0x4, add(_b,32), bl, add(freemem,96), bl) -// -// // arg[4] = exp.bits @ +96+base.length -// let size := add(96, bl) -// success := staticcall(450, 0x4, add(_e,32), el, add(freemem,size), el) -// -// // arg[5] = mod.bits @ +96+base.length+exp.length -// size := add(size,el) -// success := staticcall(450, 0x4, add(_m,32), ml, add(freemem,size), ml) -// -// switch success case 0 { invalid() } //fail where we haven't enough gas to make the call -// -// // Total size of input = 96+base.length+exp.length+mod.length -// size := add(size,ml) -// // Invoke contract 0x5, put return value right after mod.length, @ +96 -// success := staticcall(sub(gas(), 1350), 0x5, freemem, size, add(freemem, 0x60), ml) -// -// switch success case 0 { invalid() } //fail where we haven't enough gas to make the call -// -// let length := ml -// let msword_ptr := add(freemem, 0x60) -// -// ///the following code removes any leading words containing all zeroes in the result. -// for { } eq ( eq(length, 0x20), 0) { } { // for(; length!=32; length-=32) -// switch eq(mload(msword_ptr),0) // if(msword==0): -// case 1 { msword_ptr := add(msword_ptr, 0x20) } // update length pointer -// default { break } // else: loop termination. non-zero word found -// length := sub(length,0x20) -// } -// r := sub(msword_ptr,0x20) -// mstore(r, length) -// -// // point to the location of the return value (length, bits) -// //assuming mod length is multiple of 32, return value is already in the right format. -// mstore(0x40, add(add(96, freemem),ml)) //deallocate freemem pointer -// } -// } -// // ***************** END PRIVATE CORE CALCULATION FUNCTIONS ****************** -// -// -// -// -// -// // ***************** START PRIVATE HELPER FUNCTIONS ****************** -// /** @notice left shift BigNumber memory 'dividend' by 'value' bits. -// * @param bn value to shift -// * @param bits amount of bits to shift by -// * @return r result -// */ -// function _shl( -// BigNumber memory bn, -// uint bits -// ) private view returns(BigNumber memory r) { -// if(bits==0 || bn.bitlen==0) return bn; -// -// // we start by creating an empty bytes array of the size of the output, based on 'bits'. -// // for that we must get the amount of extra words needed for the output. -// uint length = bn.val.length; -// // position of bitlen in most significnat word -// uint bit_position = ((bn.bitlen-1) % 256) + 1; -// // total extra words. we check if the bits remainder will add one more word. -// uint extra_words = (bits / 256) + ( (bits % 256) >= (256 - bit_position) ? 1 : 0); -// // length of output -// uint total_length = length + (extra_words * 0x20); -// -// r.bitlen = bn.bitlen+(bits); -// r.neg = bn.neg; -// bits %= 256; -// -// -// bytes memory bn_shift; -// uint bn_shift_ptr; -// // the following efficiently creates an empty byte array of size 'total_length' -// assembly { -// let freemem_ptr := mload(0x40) // get pointer to free memory -// mstore(freemem_ptr, total_length) // store bytes length -// let mem_end := add(freemem_ptr, total_length) // end of memory -// mstore(mem_end, 0) // store 0 at memory end -// bn_shift := freemem_ptr // set pointer to bytes -// bn_shift_ptr := add(bn_shift, 0x20) // get bn_shift pointer -// mstore(0x40, add(mem_end, 0x20)) // update freemem pointer -// } -// -// // use identity for cheap copy if bits is multiple of 8. -// if(bits % 8 == 0) { -// // calculate the position of the first byte in the result. -// uint bytes_pos = ((256-(((bn.bitlen-1)+bits) % 256))-1) / 8; -// uint insize = (bn.bitlen / 8) + ((bn.bitlen % 8 != 0) ? 1 : 0); -// assembly { -// let in := add(add(mload(bn), 0x20), div(sub(256, bit_position), 8)) -// let out := add(bn_shift_ptr, bytes_pos) -// let success := staticcall(450, 0x4, in, insize, out, length) -// } -// r.val = bn_shift; -// return r; -// } -// -// -// uint mask; -// uint mask_shift = 0x100-bits; -// uint msw; -// uint msw_ptr; -// -// assembly { -// msw_ptr := add(mload(bn), 0x20) -// } -// -// // handle first word before loop if the shift adds any extra words. -// // the loop would handle it if the bit shift doesn't wrap into the next word, -// // so we check only for that condition. -// if((bit_position+bits) > 256){ -// assembly { -// msw := mload(msw_ptr) -// mstore(bn_shift_ptr, shr(mask_shift, msw)) -// bn_shift_ptr := add(bn_shift_ptr, 0x20) -// } -// } -// -// // as a result of creating the empty array we just have to operate on the words in the original bn. -// for(uint i=bn.val.length; i!=0; i-=0x20){ // for each word: -// assembly { -// msw := mload(msw_ptr) // get most significant word -// switch eq(i,0x20) // if i==32: -// case 1 { mask := 0 } // handles msword: no mask needed. -// default { mask := mload(add(msw_ptr,0x20)) } // else get mask (next word) -// msw := shl(bits, msw) // left shift current msw by 'bits' -// mask := shr(mask_shift, mask) // right shift next significant word by mask_shift -// mstore(bn_shift_ptr, or(msw,mask)) // store OR'd mask and shifted bits in-place -// msw_ptr := add(msw_ptr, 0x20) -// bn_shift_ptr := add(bn_shift_ptr, 0x20) -// } -// } -// -// r.val = bn_shift; -// } -// // ***************** END PRIVATE HELPER FUNCTIONS ****************** -//} diff --git a/contracts/utils/MemoryStack.sol b/contracts/utils/MemoryStack.sol deleted file mode 100644 index 96b2298..0000000 --- a/contracts/utils/MemoryStack.sol +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; - -import {Vector} from "@solarity/solidity-lib/libs/data-structures/memory/Vector.sol"; -import "hardhat/console.sol"; - -library MemoryStack { - using Vector for Vector.UintVector; - - struct Stack { - Vector.UintVector stack; - uint256 stackSize; - uint256 elementSize; - } - - struct StackValue { - bytes value; - } - - function init(uint256 elementSize_) internal pure returns (Stack memory) { - require(elementSize_ % 32 == 0, "MS: invalid element size"); - - return Stack({stack: Vector.newUint(), stackSize: 0, elementSize: elementSize_}); - } - - function push(Stack memory stack) internal pure returns (uint256 pointer_) { - /// @dev It's an invariant that can only be violated by direct memory manipulation - require(stack.stackSize <= stack.stack.length(), "MS: stack overflow"); - - uint256 elementSize_ = stack.elementSize; - - if (stack.stackSize == stack.stack.length()) { - assembly { - pointer_ := mload(0x40) - - /// @dev 32 bytes for metadata, 32 bytes for length, and `elementSize_` bytes for data - mstore(0x40, add(pointer_, add(elementSize_, 0x40))) - - pointer_ := add(pointer_, 0x20) - } - - stack.stack.push(pointer_); - - console.log(stack.stackSize); - - if (stack.stackSize == 33) { - revert(); - } - } else { - pointer_ = stack.stack.at(stack.stackSize); - } - - uint256 index_ = stack.stackSize; - - assembly { - mstore(sub(pointer_, 0x20), index_) - } - - ++stack.stackSize; - } - - function pop(Stack memory stack, uint256 pointer_) internal pure { - /// FIXME: still can point to another value - uint256 index_ = _checkValue(stack, pointer_); - - if (index_ + 1 < stack.stackSize) { - uint256 lastIndex_ = stack.stackSize - 1; - uint256 lastPointer_ = stack.stack.at(lastIndex_); - - assembly { - mstore(sub(lastPointer_, 0x20), index_) - } - - stack.stack.set(index_, lastPointer_); - stack.stack.set(lastIndex_, pointer_); - } - - uint256 slots_ = stack.elementSize / 32 + 1; - - assembly { - for { - let i := 0 - } lt(i, mul(slots_, 0x20)) { - i := add(i, 0x20) - } { - mstore(add(pointer_, i), 0x0) - } - } - - --stack.stackSize; - } - - function toData( - Stack memory stack, - uint256 pointer_ - ) internal view returns (bytes memory data_) { - _checkValue(stack, pointer_); - - assembly { - data_ := mload(0x40) - - let dataSize_ := add(mload(pointer_), 0x20) - - let success_ := staticcall(gas(), 0x4, pointer_, dataSize_, data_, dataSize_) - if iszero(success_) { - revert(0, 0) - } - - mstore(0x40, add(data_, dataSize_)) - } - } - - function _checkValue( - Stack memory stack, - uint256 pointer_ - ) private pure returns (uint256 index_) { - assembly { - index_ := mload(sub(pointer_, 0x20)) - } - - require(index_ < stack.stackSize, "MS: invalid index"); - require(stack.stack.at(index_) == pointer_, "MS: invalid value"); - } -} diff --git a/contracts/utils/MemoryUint.sol b/contracts/utils/MemoryUint.sol deleted file mode 100644 index 09d99c8..0000000 --- a/contracts/utils/MemoryUint.sol +++ /dev/null @@ -1,764 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; - -import {MemoryStack} from "./MemoryStack.sol"; - -struct SharedMemory { - MemoryStack.Stack stack; - MemoryStack.Stack extStack; - MemoryStack.Stack callStack; -} - -library MemoryUint { - enum Destructor { - FIRST, - SECOND, - BOTH - } - - using MemoryStack for *; - - function newUint512SharedMemory() internal pure returns (SharedMemory memory mem_) { - mem_.stack = MemoryStack.init(64); - mem_.extStack = MemoryStack.init(128); - mem_.callStack = MemoryStack.init(512); - - return mem_; - } - - function toData(uint256 value_) internal pure returns (bytes memory data_) { - assembly { - data_ := value_ - } - } - - function zero(SharedMemory memory mem) internal pure returns (uint256) { - return _newUint(mem, 0); - } - - function one(SharedMemory memory mem) internal pure returns (uint256) { - return _newUint(mem, 1); - } - - function two(SharedMemory memory mem) internal pure returns (uint256) { - return _newUint(mem, 2); - } - - function three(SharedMemory memory mem) internal pure returns (uint256) { - return _newUint(mem, 3); - } - - function newUint512( - SharedMemory memory mem_, - bytes memory data_ - ) internal view returns (uint256 u512_) { - require(data_.length <= 64, "MU: data is too large"); - _checkMemory(mem_, 64); - - /// TODO: Can we pass here mem as a pointer? - return _initUint(mem_, data_); - } - - function destruct(SharedMemory memory mem_, uint256 u512_) internal pure { - _destruct(mem_, u512_, _StackType._UINT); - } - - function add( - SharedMemory memory mem_, - uint256 a_, - uint256 b_ - ) internal pure returns (uint256 r_) { - _checkMemory(mem_, 64); - - return _add(mem_, a_, b_); - } - - function sub( - SharedMemory memory mem_, - uint256 a_, - uint256 b_ - ) internal pure returns (uint256 r_) { - _checkMemory(mem_, 64); - - return _sub(mem_, a_, b_); - } - - function mod( - SharedMemory memory mem_, - uint256 a_, - uint256 m_ - ) internal view returns (uint256 r_) { - _checkMemory(mem_, 64); - - return _mod(mem_, a_, m_); - } - - function mul( - SharedMemory memory mem_, - uint256 a_, - uint256 b_ - ) internal view returns (uint256 r_) { - _checkMemory(mem_, 64); - - uint256 rExt_ = _mul(mem_, a_, b_); - - r_ = _cut(mem_, rExt_); - - _destruct(mem_, rExt_, _StackType._EXT_UINT); - } - - function modadd( - SharedMemory memory mem_, - uint256 a_, - uint256 b_, - uint256 m_ - ) internal view returns (uint256 r_) { - _checkMemory(mem_, 64); - - uint256 aExt_ = _extend(mem_, a_); - uint256 bExt_ = _extend(mem_, b_); - - uint256 sum_ = _add(mem_, aExt_, bExt_); - - r_ = _mod(mem_, sum_, m_); - - _destruct(mem_, aExt_, _StackType._EXT_UINT); - _destruct(mem_, bExt_, _StackType._EXT_UINT); - _destruct(mem_, sum_, _StackType._EXT_UINT); - } - - function modadd( - SharedMemory memory mem_, - uint256 a_, - uint256 b_, - uint256 m_, - Destructor d_ - ) internal view returns (uint256 r_) { - r_ = modadd(mem_, a_, b_, m_); - - if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { - _destruct(mem_, a_, _StackType._UINT); - } - - if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { - _destruct(mem_, b_, _StackType._UINT); - } - } - - function modsub( - SharedMemory memory mem_, - uint256 a_, - uint256 b_, - uint256 m_ - ) internal view returns (uint256 r_) { - _checkMemory(mem_, 64); - - int cmp_ = _cmp(a_, b_); - - uint256 diff_ = cmp_ >= 0 ? _sub(mem_, a_, b_) : _sub(mem_, b_, a_); - uint256 modDiff_ = _mod(mem_, diff_, m_); - - _destruct(mem_, diff_, _StackType._UINT); - - if (cmp_ >= 0) { - return modDiff_; - } - - r_ = _sub(mem_, m_, modDiff_); - - _destruct(mem_, modDiff_, _StackType._UINT); - } - - function modsub( - SharedMemory memory mem_, - uint256 a_, - uint256 b_, - uint256 m_, - Destructor d_ - ) internal view returns (uint256 r_) { - r_ = modsub(mem_, a_, b_, m_); - - if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { - _destruct(mem_, a_, _StackType._UINT); - } - - if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { - _destruct(mem_, b_, _StackType._UINT); - } - } - - function modmul( - SharedMemory memory mem_, - uint256 a_, - uint256 b_, - uint256 m_ - ) internal view returns (uint256 r_) { - _checkMemory(mem_, 64); - - uint256 rExt_ = _mul(mem_, a_, b_); - - r_ = _mod(mem_, rExt_, m_); - - _destruct(mem_, rExt_, _StackType._EXT_UINT); - } - - function modmul( - SharedMemory memory mem_, - uint256 a_, - uint256 b_, - uint256 m_, - Destructor d_ - ) internal view returns (uint256 r_) { - r_ = modmul(mem_, a_, b_, m_); - - if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { - _destruct(mem_, a_, _StackType._UINT); - } - - if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { - _destruct(mem_, b_, _StackType._UINT); - } - } - - function modexp( - SharedMemory memory mem_, - uint256 a_, - uint256 e_, - uint256 m_ - ) internal view returns (uint256 r_) { - _checkMemory(mem_, 64); - - return _modexp(mem_, a_, e_, m_); - } - - function modexp( - SharedMemory memory mem_, - uint256 a_, - uint256 e_, - uint256 m_, - Destructor d_ - ) internal view returns (uint256 r_) { - r_ = modexp(mem_, a_, e_, m_); - - if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { - _destruct(mem_, a_, _StackType._UINT); - } - - if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { - _destruct(mem_, e_, _StackType._UINT); - } - } - - function modinv( - SharedMemory memory mem_, - uint256 a_, - uint256 m_ - ) internal view returns (uint256 r_) { - _checkMemory(mem_, 64); - - return _modinv(mem_, a_, m_); - } - - function moddiv( - SharedMemory memory mem_, - uint256 a_, - uint256 b_, - uint256 m_ - ) internal view returns (uint256 r_) { - _checkMemory(mem_, 64); - - uint256 bInv_ = _modinv(mem_, b_, m_); - uint256 rExt_ = _mul(mem_, a_, bInv_); - - r_ = _mod(mem_, rExt_, m_); - - _destruct(mem_, rExt_, _StackType._EXT_UINT); - _destruct(mem_, bInv_, _StackType._UINT); - } - - function moddiv( - SharedMemory memory mem_, - uint256 a_, - uint256 b_, - uint256 m_, - Destructor d_ - ) internal view returns (uint256 r_) { - r_ = moddiv(mem_, a_, b_, m_); - - if (d_ == Destructor.BOTH || d_ == Destructor.FIRST) { - _destruct(mem_, a_, _StackType._UINT); - } - - if (d_ == Destructor.BOTH || d_ == Destructor.SECOND) { - _destruct(mem_, b_, _StackType._UINT); - } - } - - function cmp(SharedMemory memory mem_, uint256 a_, uint256 b_) internal pure returns (int) { - _checkMemory(mem_, 64); - - return _cmp(a_, b_); - } - - /// @dev a_, b_ and r_ are of the same size - function _add( - SharedMemory memory mem_, - uint256 a_, - uint256 b_ - ) private pure returns (uint256 r_) { - r_ = _new(mem_, _valueType(mem_, a_)); - - assembly { - let memSize_ := mload(a_) - - mstore(r_, memSize_) - - let aPtr_ := add(a_, memSize_) - let bPtr_ := add(b_, memSize_) - let rPtr_ := add(r_, memSize_) - - let carry_ := 0 - - for { - let i := memSize_ - } eq(iszero(i), 0) { - i := sub(i, 0x20) - } { - let aWord_ := mload(aPtr_) - let bWord_ := mload(bPtr_) - let rWord_ := add(add(aWord_, bWord_), carry_) - - carry_ := and( - eq(gt(rWord_, aWord_), 0), - or(eq(iszero(carry_), 0), eq(iszero(bWord_), 0)) - ) - - mstore(rPtr_, rWord_) - - aPtr_ := sub(aPtr_, 0x20) - bPtr_ := sub(bPtr_, 0x20) - rPtr_ := sub(rPtr_, 0x20) - } - } - } - - /// @dev a_, b_ and r_ are of the same size, a >= b - function _sub( - SharedMemory memory mem_, - uint256 a_, - uint256 b_ - ) private pure returns (uint256 r_) { - r_ = _new(mem_, _valueType(mem_, a_)); - - assembly { - let memSize_ := mload(a_) - - mstore(r_, memSize_) - - let aPtr_ := add(a_, memSize_) - let bPtr_ := add(b_, memSize_) - let rPtr_ := add(r_, memSize_) - - let carry_ := 0 - - for { - let i := memSize_ - } eq(iszero(i), 0) { - i := sub(i, 0x20) - } { - let aWord_ := mload(aPtr_) - let bWord_ := mload(bPtr_) - - mstore(rPtr_, sub(sub(aWord_, bWord_), carry_)) - - carry_ := or( - lt(aWord_, add(bWord_, carry_)), - and(eq(bWord_, sub(0, 1)), eq(carry_, 1)) - ) - - aPtr_ := sub(aPtr_, 0x20) - bPtr_ := sub(bPtr_, 0x20) - rPtr_ := sub(rPtr_, 0x20) - } - } - } - - /// @dev a_, b_ are of the same size, r_ is extended - function _mul( - SharedMemory memory mem_, - uint256 a_, - uint256 b_ - ) private pure returns (uint256 r_) { - uint256 rBig_ = _new(mem_, _StackType._CALL); - r_ = _new(mem_, _StackType._EXT_UINT); - - assembly { - function get_arg(a, i) -> result { - let idx := div(i, 0x20) - let word := mload(add(add(a, 0x20), mul(shr(1, idx), 0x20))) - - switch and(idx, 1) - case 0 { - result := shr(128, word) - } - case 1 { - result := shr(128, shl(128, word)) - } - } - - function add_res(r, i, val) { - let ptr := add(r, add(i, 0x20)) - - mstore(ptr, add(mload(ptr), val)) - } - - let argSize_ := shl(1, mload(a_)) // 128 - let resSize_ := shl(1, argSize_) // 256 - - for { - let i := 0 - } lt(i, argSize_) { - i := add(i, 0x20) - } { - for { - let j := 0 - } lt(j, argSize_) { - j := add(j, 0x20) - } { - let a_i_ := get_arg(a_, i) - let b_j_ := get_arg(b_, j) - - let val_ := mul(a_i_, b_j_) - - add_res(rBig_, add(i, j), val_) - } - } - - let rBigPtr_ := add(rBig_, sub(resSize_, 0x20)) - - for { - let i := 0x20 - } lt(i, resSize_) { - i := add(i, 0x20) - } { - let rBigPtrNext_ := sub(rBigPtr_, 0x20) - - let carry_ := shr(128, mload(rBigPtr_)) - - mstore(rBigPtr_, shr(128, shl(128, mload(rBigPtr_)))) - mstore(rBigPtrNext_, add(mload(rBigPtrNext_), carry_)) - - rBigPtr_ := rBigPtrNext_ - } - - for { - let i := 0x00 - } lt(i, resSize_) { - i := add(i, 0x40) - } { - let rPtr_ := add(add(r_, 0x20), shr(1, i)) - - let highBits_ := mload(add(rBig_, i)) - let lowBits_ := mload(add(rBig_, add(i, 0x20))) - - mstore(rPtr_, add(shl(128, highBits_), lowBits_)) - } - - /// FIXME: fix - mstore(r_, argSize_) - } - - _destruct(mem_, rBig_, _StackType._CALL); - } - - function _mod( - SharedMemory memory mem_, - uint256 a_, - uint256 m_ - ) private view returns (uint256 r_) { - uint256 one_ = _newUint(mem_, 1); - - r_ = _modexp(mem_, a_, one_, m_); - - _destruct(mem_, one_, _StackType._UINT); - } - - /// @dev a_, e_, m_ can be of different sizes - function _modexp( - SharedMemory memory mem_, - uint256 a_, - uint256 e_, - uint256 m_ - ) private view returns (uint256 r_) { - r_ = _new(mem_, _valueType(mem_, m_)); - uint256 call_ = _new(mem_, _StackType._CALL); - - assembly { - let aSize_ := mload(a_) - let eSize_ := mload(e_) - let mSize_ := mload(m_) - - mstore(call_, aSize_) - mstore(add(call_, 0x20), eSize_) - mstore(add(call_, 0x40), mSize_) - - let offset_ := 0x60 - - if iszero(staticcall(gas(), 0x4, add(a_, 0x20), aSize_, add(call_, offset_), aSize_)) { - revert(0, 0) - } - - offset_ := add(offset_, aSize_) - - if iszero(staticcall(gas(), 0x4, add(e_, 0x20), eSize_, add(call_, offset_), eSize_)) { - revert(0, 0) - } - - offset_ := add(offset_, eSize_) - - if iszero(staticcall(gas(), 0x4, add(m_, 0x20), mSize_, add(call_, offset_), mSize_)) { - revert(0, 0) - } - - offset_ := add(offset_, mSize_) - - mstore(r_, mSize_) - - if iszero(staticcall(gas(), 0x5, call_, offset_, add(r_, 0x20), mSize_)) { - revert(0, 0) - } - } - - _destruct(mem_, call_, _StackType._CALL); - } - - function _modinv( - SharedMemory memory mem_, - uint256 a_, - uint256 m_ - ) private view returns (uint256 r_) { - uint256 two_ = _newUint(mem_, 2); - - require(_cmp(m_, two_) >= 0, "MU: invalid modulus"); - - uint256 exponent_ = _sub(mem_, m_, two_); - - r_ = _modexp(mem_, a_, exponent_, m_); - - _destruct(mem_, two_, _StackType._UINT); - _destruct(mem_, exponent_, _StackType._UINT); - } - - /// @dev a_ and b_ are of the same size - function _cmp(uint256 a_, uint256 b_) private pure returns (int256 cmp_) { - assembly { - let aSize_ := mload(a_) - let aPtr_ := add(a_, 0x20) - let bPtr_ := add(b_, 0x20) - - for { - let i := 0 - } lt(i, aSize_) { - i := add(i, 0x20) - } { - let aWord_ := mload(add(aPtr_, i)) - let bWord_ := mload(add(bPtr_, i)) - - if gt(aWord_, bWord_) { - cmp_ := 1 - break - } - - if gt(bWord_, aWord_) { - cmp_ := sub(0, 1) - break - } - } - } - - return cmp_; - } - - function _extend( - SharedMemory memory mem_, - uint256 value_ - ) private view returns (uint256 valueExt_) { - valueExt_ = _new(mem_, _StackType._EXT_UINT); - - uint256 memSize_ = _memSize(mem_, _StackType._UINT); - uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); - - assembly { - mstore(valueExt_, extMemSize_) - - let offset_ := sub(extMemSize_, memSize_) - - if iszero( - staticcall( - gas(), - 0x4, - add(value_, 0x20), - memSize_, - add(add(valueExt_, 0x20), offset_), - memSize_ - ) - ) { - revert(0, 0) - } - } - } - - function _cut(SharedMemory memory mem_, uint256 a_) private view returns (uint256 r_) { - r_ = _new(mem_, _StackType._UINT); - - uint256 memSize_ = _memSize(mem_, _StackType._UINT); - uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); - - assembly { - mstore(r_, memSize_) - - let offset_ := add(sub(extMemSize_, memSize_), 0x20) - - if iszero( - staticcall(gas(), 0x4, add(a_, offset_), memSize_, add(r_, 0x20), memSize_) - ) { - revert(0, 0) - } - } - } - - enum _StackType { - _UINT, - _EXT_UINT, - _CALL - } - - function _checkMemory(SharedMemory memory mem_, uint256 bytesCount_) private pure { - require(mem_.stack.elementSize == bytesCount_, "MU: invalid memory"); - } - - function _new( - SharedMemory memory mem_, - _StackType stackType_ - ) private pure returns (uint256 value_) { - if (stackType_ == _StackType._UINT) { - return mem_.stack.push(); - } - - if (stackType_ == _StackType._EXT_UINT) { - return mem_.extStack.push(); - } - - return mem_.callStack.push(); - } - - function _destruct( - SharedMemory memory mem_, - uint256 value_, - _StackType stackType_ - ) private pure { - if (stackType_ == _StackType._UINT) { - mem_.stack.pop(value_); - return; - } - - if (stackType_ == _StackType._EXT_UINT) { - mem_.extStack.pop(value_); - return; - } - - mem_.callStack.pop(value_); - } - - function _memSize( - SharedMemory memory mem_, - _StackType stackType_ - ) private pure returns (uint256) { - if (stackType_ == _StackType._UINT) { - return mem_.stack.elementSize; - } - - if (stackType_ == _StackType._EXT_UINT) { - return mem_.extStack.elementSize; - } - - return mem_.callStack.elementSize; - } - - function _valueType( - SharedMemory memory mem_, - uint256 value_ - ) private pure returns (_StackType) { - uint256 length_; - assembly { - length_ := mload(value_) - } - - if (length_ == mem_.stack.elementSize) { - return _StackType._UINT; - } - - if (length_ == mem_.extStack.elementSize) { - return _StackType._EXT_UINT; - } - - return _StackType._CALL; - } - - function _newUint(SharedMemory memory mem_, uint256 value_) private pure returns (uint256 r_) { - uint256 memSize_ = _memSize(mem_, _StackType._UINT); - - r_ = _new(mem_, _StackType._UINT); - - assembly { - mstore(r_, memSize_) - mstore(add(r_, memSize_), value_) - } - } - - function _newMaxUint(SharedMemory memory mem_) private pure returns (uint256 r_) { - uint256 extMemSize_ = _memSize(mem_, _StackType._EXT_UINT); - - r_ = _new(mem_, _StackType._EXT_UINT); - - assembly { - mstore(r_, extMemSize_) - - for { - let i := 0 - } lt(i, extMemSize_) { - i := add(i, 0x20) - } { - mstore(add(r_, add(i, 0x20)), sub(0, 1)) - } - } - } - - function _initUint( - SharedMemory memory mem_, - bytes memory data_ - ) private view returns (uint256 r_) { - r_ = _new(mem_, _StackType._UINT); - - uint256 uSize_ = _memSize(mem_, _StackType._UINT); - - assembly { - let dataSize_ := mload(data_) - let offset_ := sub(uSize_, dataSize_) - - mstore(r_, uSize_) - - let success_ := staticcall( - gas(), - 0x4, - add(data_, 0x20), - dataSize_, - add(add(r_, 0x20), offset_), - dataSize_ - ) - if iszero(success_) { - revert(0, 0) - } - } - } -} diff --git a/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts b/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts new file mode 100644 index 0000000..54c7dc5 --- /dev/null +++ b/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts @@ -0,0 +1,35 @@ +import { ethers } from "hardhat"; +import { expect } from "chai"; +import { Reverter } from "@/test/helpers/"; + +import { PECDSA384SHA2Authenticator } from "@ethers-v6"; + +describe("PECDSA384SHA2Authenticator", () => { + const reverter = new Reverter(); + + let auth384: PECDSA384SHA2Authenticator; + + before("setup", async () => { + const PECDSA384SHA2Authenticator = await ethers.getContractFactory("PECDSA384SHA2Authenticator"); + + auth384 = await PECDSA384SHA2Authenticator.deploy(); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe("#authenticate", () => { + it("should authenticate passport - secp384r1 & sha2 new", async () => { + const challenge = + "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; + + const r = "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63"; + const s = "0xf1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd"; + const x = "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6"; + const y = "0x1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; + + expect(await auth384.authenticate(challenge, { r, s, x, y })).to.be.true; + }); + }); +}); diff --git a/test/passport/authenticators/PECDSAAuthenticator.test.ts b/test/passport/authenticators/PECDSAAuthenticator.test.ts deleted file mode 100644 index 09a815e..0000000 --- a/test/passport/authenticators/PECDSAAuthenticator.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { ethers } from "hardhat"; -import { toBeHex as hex } from "ethers"; -import { expect } from "chai"; -import { Reverter } from "@/test/helpers/"; -import { inverseMod, toAffinePoint, multiplyScalar, addProj, n, p, gx, gy, modmul } from "@/test/helpers/"; - -import { - PECDSASHA1Authenticator, - PECDSASHA2Authenticator, - PECDSASHA2NewAuthenticator, - PECDSASHA1U384Authenticator, -} from "@ethers-v6"; - -describe("PECDSAAuthenticator", () => { - const reverter = new Reverter(); - - let authSha1: PECDSASHA1Authenticator; - let authSha2: PECDSASHA2Authenticator; - let authSha2New: PECDSASHA2NewAuthenticator; - let authU384: PECDSASHA1U384Authenticator; - - before("setup", async () => { - const PECDSASHA1Authenticator = await ethers.getContractFactory("PECDSASHA1Authenticator"); - const PECDSASHA2Authenticator = await ethers.getContractFactory("PECDSASHA2Authenticator"); - const PECDSASHA2NewAuthenticator = await ethers.getContractFactory("PECDSASHA2NewAuthenticator"); - const PECDSASHA1U384Authenticator = await ethers.getContractFactory("PECDSASHA1U384Authenticator"); - - authSha1 = await PECDSASHA1Authenticator.deploy(); - authSha2 = await PECDSASHA2Authenticator.deploy(); - authSha2New = await PECDSASHA2NewAuthenticator.deploy(); - authU384 = await PECDSASHA1U384Authenticator.deploy(); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe("#authenticate", () => { - it.only("should authenticate passport - brainpool256r1 & sha1", async () => { - const challenge = "0xe7938ea62eb1980a"; - - const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; - const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; - const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; - const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; - - expect(await authSha1.authenticate(challenge, r, s, x, y)).to.be.true; - }); - - it("should authenticate passport - brainpool256r1 & sha2", async () => { - const challenge = "0xe7938ea62eb1980a"; - - const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; - const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; - const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; - const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; - - expect(await authSha2.authenticate(challenge, r, s, x, y)).to.be.true; - }); - - it.only("should authenticate passport - secp384r1 & sha2 new", async () => { - const challenge = - "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; - - const r = "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63"; - const s = "0xf1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd"; - const x = "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6"; - const y = "0x1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; - - // const challenge = "0xe7938ea62eb1980a"; - // - // const r = "0x13DCD0CCE676DFB4C2EF2B26F3AC8BB640146391C12EC80E052ABA2D617A5888"; - // const s = "0x4060930A62757DC2003F4CAA38E9CFF44001E2B3D7286E03CA119B1AD7A680B1"; - // const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; - // const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; - - //await authSha2New.forTest(y); - expect(await authU384.authenticate(challenge, { r, s, x, y })).to.be.true; - - // console.log(gx, gy, modmul(BigInt(ethers.sha256(challenge)), sInv, n)); - - // const sInv = inverseMod(BigInt(s), n); - // const { x: x1, y: y1 } = multiplyScalar(gx, gy, modmul(BigInt(ethers.sha256(challenge)), sInv, n)); - // // const points1 = await authSha2._multiplyScalarPartial( - // // hex(gx), - // // hex(gy), - // // hex(modmul(BigInt(ethers.sha256(challenge)), sInv, n)), - // // ); - // // const points2 = await authSha2._multiplyScalarPartial( - // // hex(gx), - // // hex(gy), - // // hex(modmul(BigInt(ethers.sha256(challenge)), sInv, n)), - // // ); - - // const { x: x2, y: y2 } = multiplyScalar(BigInt(x), BigInt(y), modmul(BigInt(r), sInv, n)); - // const { - // x: x0, - // y: y0, - // z: z0, - // } = addProj( - // BigInt(points1.x1.val), - // BigInt(points1.y1.val), - // 1n, - // BigInt(points2.x1.val), - // BigInt(points2.y1.val), - // 1n, - // ); - - // const { x: xP } = toAffinePoint(x0, y0, z0); - // const Px = inverseMod(1n % p, p); - - // expect(await authSha2.authenticate(r, s, x, y, hex(xP), hex(Px))).to.be.true; - - // console.log("_multiplyScalarPartial+", new Intl.NumberFormat("en-US").format(gas1)); - // console.log("_multiplyScalarPartial-", new Intl.NumberFormat("en-US").format(gas2)); - }); - }); -}); diff --git a/test/passport/authenticators/PECDSASHA1Authenticator.test.ts b/test/passport/authenticators/PECDSASHA1Authenticator.test.ts index 0ec54c9..97a27d9 100644 --- a/test/passport/authenticators/PECDSASHA1Authenticator.test.ts +++ b/test/passport/authenticators/PECDSASHA1Authenticator.test.ts @@ -7,12 +7,12 @@ import { PECDSASHA1Authenticator } from "@ethers-v6"; describe("PECDSASHA1Authenticator", () => { const reverter = new Reverter(); - let auth: PECDSASHA1Authenticator; + let auth256: PECDSASHA1Authenticator; before("setup", async () => { const PECDSASHA1Authenticator = await ethers.getContractFactory("PECDSASHA1Authenticator"); - auth = await PECDSASHA1Authenticator.deploy(); + auth256 = await PECDSASHA1Authenticator.deploy(); await reverter.snapshot(); }); @@ -28,7 +28,7 @@ describe("PECDSASHA1Authenticator", () => { const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; - expect(await auth.authenticate(challenge, r, s, x, y)).to.be.true; + expect(await auth256.authenticate(challenge, r, s, x, y)).to.be.true; }); }); }); diff --git a/test/utils/Stack.test.ts b/test/utils/Stack.test.ts deleted file mode 100644 index 256708d..0000000 --- a/test/utils/Stack.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ethers } from "hardhat"; - -import { StackMock } from "@ethers-v6"; - -import { getPoseidon, Reverter } from "@/test/helpers/"; - -describe("Stack", () => { - const reverter = new Reverter(); - - let stack: StackMock; - - before("setup", async () => { - const Stack = await ethers.getContractFactory("StackMock"); - - stack = await Stack.deploy(); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe("stack", () => { - it("stack", async () => { - const y = BigInt("0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"); - const p = BigInt("0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"); - - console.log(await stack.modmul("0x" + y.toString(16), "0x" + y.toString(16), "0x" + p.toString(16))); - }); - }); -}); From 612fb4ce1b59ac09753f2de9de7858ed7c042047 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Thu, 24 Oct 2024 19:44:03 +0300 Subject: [PATCH 34/45] rm stack mock --- contracts/mock/utils/StackMock.sol | 73 ------------------------------ 1 file changed, 73 deletions(-) delete mode 100644 contracts/mock/utils/StackMock.sol diff --git a/contracts/mock/utils/StackMock.sol b/contracts/mock/utils/StackMock.sol deleted file mode 100644 index dce5d7c..0000000 --- a/contracts/mock/utils/StackMock.sol +++ /dev/null @@ -1,73 +0,0 @@ -// // SPDX-License-Identifier: MIT -// pragma solidity ^0.8.4; - -// import {MemoryStack} from "../../utils/MemoryStack.sol"; -// import {MemoryUint} from "../../utils/MemoryUint.sol"; - -// contract StackMock { -// using MemoryStack for MemoryStack.Stack; -// using MemoryUint for *; - -// //// let t: bigint; -// //// let u: bigint; -// //// let v: bigint; -// //// let w: bigint; -// //// -// //// if (isZeroCurve(x0, y0)) { -// //// return zeroProj(); -// //// } -// //// -// //// u = modmul(y0, z0, p); -// //// u = modmul(u, 2n, p); -// //// -// //// v = modmul(u, x0, p); -// //// v = modmul(v, y0, p); -// //// v = modmul(v, 2n, p); -// //// -// //// x0 = modmul(x0, x0, p); -// //// t = modmul(x0, BigInt(3), p); -// //// -// //// z0 = modmul(z0, z0, p); -// //// z0 = modmul(z0, a, p); -// //// t = (t + z0) % p; -// //// -// //// w = modmul(t, t, p); -// //// x0 = modmul(2n, v, p); -// //// w = (w + (p - x0)) % p; -// //// -// //// x0 = (v + (p - w)) % p; -// //// x0 = modmul(t, x0, p); -// //// y0 = modmul(y0, u, p); -// //// y0 = modmul(y0, y0, p); -// //// y0 = modmul(2n, y0, p); -// //// let y1 = (x0 + (p - y0)) % p; -// //// -// //// let x1 = modmul(u, w, p); -// //// -// //// let z1 = modmul(u, u, p); -// //// z1 = modmul(z1, u, p); -// //// -// function mock() external view returns (MemoryUint.Uint512 memory) { -// MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); - -// MemoryUint.Uint512 memory a_ = mem_.newUint512(hex"05"); -// MemoryUint.Uint512 memory b_ = mem_.newUint512(hex"07"); -// MemoryUint.Uint512 memory m_ = mem_.newUint512(hex"0A"); - -// return MemoryUint.moddiv(mem_, a_, b_, m_); -// } - -// function modmul( -// bytes memory a_, -// bytes memory b_, -// bytes memory m_ -// ) external view returns (MemoryUint.Uint512 memory) { -// MemoryUint.SharedMemory memory mem_ = MemoryUint.newUint512SharedMemory(); - -// MemoryUint.Uint512 memory a_ = mem_.newUint512(a_); -// MemoryUint.Uint512 memory b_ = mem_.newUint512(b_); -// MemoryUint.Uint512 memory m_ = mem_.newUint512(m_); - -// return MemoryUint.modmul(mem_, a_, b_, m_); -// } -// } From 52d7961a2035d6398757a841caa3f986b4396c96 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Thu, 24 Oct 2024 19:54:23 +0300 Subject: [PATCH 35/45] fixes --- .../PECDSA384SHA2Authenticator.sol | 16 ++++++++-------- .../authenticators/PECDSASHA1Authenticator.sol | 6 +++--- contracts/utils/U384.sol | 2 ++ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol b/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol index ba1b468..6901757 100644 --- a/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol +++ b/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol @@ -72,14 +72,14 @@ contract PECDSA384SHA2Authenticator { }); /// @dev accept s only from the lower part of the curve -// if ( -// U384.eqInteger(_inputs.r, 0) || -// U384.cmp(_inputs.r, params.n) != -1 || -// U384.eqInteger(_inputs.s, 0) || -// U384.cmp(_inputs.s, params.lowSmax) == 1 -// ) { -// return false; -// } + if ( + U384.eqInteger(_inputs.r, 0) || + U384.cmp(_inputs.r, params.n) >= 0 || + U384.eqInteger(_inputs.s, 0) || + U384.cmp(_inputs.s, params.lowSmax) == 1 + ) { + return false; + } if (!_isOnCurve(params.call, params.p, params.a, params.b, _inputs.x, _inputs.y)) { return false; diff --git a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol index 1d65d1d..4265052 100644 --- a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol @@ -31,9 +31,9 @@ contract PECDSASHA1Authenticator { uint256 y ) external pure returns (bool) { /// @dev accept s only from the lower part of the curve -// if (r == 0 || r >= n || s == 0 || s > lowSmax) { -// return false; -// } + if (r == 0 || r >= n || s == 0 || s > lowSmax) { + return false; + } if (!_isOnCurve(x, y)) { return false; diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 52d4693..bec890f 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -21,6 +21,8 @@ library U384 { function init(bytes memory from_) internal pure returns (uint256 handler_) { unchecked { + require(from_.length == 64, "U384: not 384"); + handler_ = _allocate(SHORT_ALLOCATION); assembly { From 736fe2be40cb3c89e865c9f47ff38148b9c141dd Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Thu, 24 Oct 2024 20:03:19 +0300 Subject: [PATCH 36/45] fix --- contracts/utils/U384.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index bec890f..ad58a54 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -21,7 +21,7 @@ library U384 { function init(bytes memory from_) internal pure returns (uint256 handler_) { unchecked { - require(from_.length == 64, "U384: not 384"); + require(from_.length == 48, "U384: not 384"); handler_ = _allocate(SHORT_ALLOCATION); From 3c836ec700be1af2d9ac155aa359b9f08b30b5b6 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 25 Oct 2024 14:41:28 +0300 Subject: [PATCH 37/45] fixed test --- .../passport/authenticators/PECDSA384SHA2Authenticator.sol | 2 +- test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol b/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol index 6901757..1843798 100644 --- a/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol +++ b/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol @@ -76,7 +76,7 @@ contract PECDSA384SHA2Authenticator { U384.eqInteger(_inputs.r, 0) || U384.cmp(_inputs.r, params.n) >= 0 || U384.eqInteger(_inputs.s, 0) || - U384.cmp(_inputs.s, params.lowSmax) == 1 + U384.cmp(_inputs.s, params.lowSmax) > 0 ) { return false; } diff --git a/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts b/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts index 54c7dc5..128937a 100644 --- a/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts +++ b/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts @@ -25,7 +25,7 @@ describe("PECDSA384SHA2Authenticator", () => { "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; const r = "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63"; - const s = "0xf1f85ce14adeb8671a134fcd1b6a7a0a2c2ad4908b27428dcb65ed17afd07f6524a7d892015394132b48bb3a2bdd1edd"; + const s = "0x0e07a31eb5214798e5ecb032e49585f5d3d52b6f74d8bd71fbfd606a4466ae7a33723520475d1367c1a35e30a0e80a96"; const x = "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6"; const y = "0x1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; From e73908a85fdec442c84cb404d69daa92a0f38da9 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 25 Oct 2024 18:34:42 +0300 Subject: [PATCH 38/45] mv ecdsa to certificates --- .../signers/CECDSASHA2Signer.sol} | 52 +++++++++---------- contracts/utils/U384.sol | 21 ++++++++ .../signers/CECDSASHA2Signer.test.ts | 36 +++++++++++++ .../PECDSA384SHA2Authenticator.test.ts | 35 ------------- test/registration/Registration.test.ts | 2 +- 5 files changed, 82 insertions(+), 64 deletions(-) rename contracts/{passport/authenticators/PECDSA384SHA2Authenticator.sol => certificate/signers/CECDSASHA2Signer.sol} (92%) create mode 100644 test/certificate/signers/CECDSASHA2Signer.test.ts delete mode 100644 test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts diff --git a/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol b/contracts/certificate/signers/CECDSASHA2Signer.sol similarity index 92% rename from contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol rename to contracts/certificate/signers/CECDSASHA2Signer.sol index 1843798..7913398 100644 --- a/contracts/passport/authenticators/PECDSA384SHA2Authenticator.sol +++ b/contracts/certificate/signers/CECDSASHA2Signer.sol @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {U384} from "../../utils/U384.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {U384} from "../../utils/U384.sol"; +import "hardhat/console.sol"; /** * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol */ -contract PECDSA384SHA2Authenticator { +contract CECDSASHA2Signer is Initializable { using U384 for *; struct Parameters { @@ -22,34 +24,28 @@ contract PECDSA384SHA2Authenticator { } struct Inputs { - bytes r; - bytes s; - bytes x; - bytes y; - } - - struct _Inputs { uint256 r; uint256 s; uint256 x; uint256 y; } + function __CECDSASHA2Signer_init() external initializer {} + /** * @notice Checks active authentication of a passport. ECDSA active authentication is an ECDSA signature of * raw SHA1 hash of challenge bytes. Usually brainpool256r1 elliptic curve is used. */ - function authenticate( - bytes memory challenge, - Inputs memory inputs + function verifyICAOSignature( + bytes memory x509SignedAttributes_, + bytes memory icaoMemberSignature_, + bytes memory icaoMemberKey_ ) external view returns (bool) { unchecked { - _Inputs memory _inputs; + Inputs memory inputs; - _inputs.r = U384.init(inputs.r); - _inputs.s = U384.init(inputs.s); - _inputs.x = U384.init(inputs.x); - _inputs.y = U384.init(inputs.y); + (inputs.r, inputs.s) = U384.init2(icaoMemberSignature_); + (inputs.x, inputs.y) = U384.init2(icaoMemberKey_); // brainpool256r1 parameters Parameters memory params = Parameters({ @@ -73,31 +69,31 @@ contract PECDSA384SHA2Authenticator { /// @dev accept s only from the lower part of the curve if ( - U384.eqInteger(_inputs.r, 0) || - U384.cmp(_inputs.r, params.n) >= 0 || - U384.eqInteger(_inputs.s, 0) || - U384.cmp(_inputs.s, params.lowSmax) > 0 + U384.eqInteger(inputs.r, 0) || + U384.cmp(inputs.r, params.n) >= 0 || + U384.eqInteger(inputs.s, 0) || + U384.cmp(inputs.s, params.lowSmax) > 0 ) { return false; } - if (!_isOnCurve(params.call, params.p, params.a, params.b, _inputs.x, _inputs.y)) { + if (!_isOnCurve(params.call, params.p, params.a, params.b, inputs.x, inputs.y)) { return false; } - uint256 message = uint256(sha256(challenge)).init(); + uint256 message = uint256(sha256(x509SignedAttributes_)).init(); (uint256 x1, uint256 y1) = _multiplyScalar( params, params.gx, params.gy, - U384.moddiv(params.call, message, _inputs.s, params.n) + U384.moddiv(params.call, message, inputs.s, params.n) ); (uint256 x2, uint256 y2) = _multiplyScalar( params, - _inputs.x, - _inputs.y, - U384.moddiv(params.call, _inputs.r, _inputs.s, params.n) + inputs.x, + inputs.y, + U384.moddiv(params.call, inputs.r, inputs.s, params.n) ); uint256[3] memory P = _addAndReturnProjectivePoint( @@ -123,7 +119,7 @@ contract PECDSA384SHA2Authenticator { params.p ); - return U384.eq(U384.mod(params.call, Px, params.n), _inputs.r); + return U384.eq(U384.mod(params.call, Px, params.n), inputs.r); } } diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index ad58a54..11622eb 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -35,6 +35,27 @@ library U384 { } } + function init2(bytes memory from2_) internal pure returns (uint256 handler1_, uint256 handler2_) { + unchecked { + require(from2_.length == 96, "U384: not 768"); + + handler1_ = _allocate(SHORT_ALLOCATION); + handler2_ = _allocate(SHORT_ALLOCATION); + + assembly { + mstore(handler1_, 0x00) + mstore(add(handler1_, 0x10), mload(add(from2_, 0x20))) + mstore(add(handler1_, 0x20), mload(add(from2_, 0x30))) + + mstore(handler2_, 0x00) + mstore(add(handler2_, 0x10), mload(add(from2_, 0x50))) + mstore(add(handler2_, 0x20), mload(add(from2_, 0x60))) + } + + return (handler1_, handler2_); + } + } + function assign(uint256 to_, uint256 from_) internal pure { assembly { mstore(to_, mload(from_)) diff --git a/test/certificate/signers/CECDSASHA2Signer.test.ts b/test/certificate/signers/CECDSASHA2Signer.test.ts new file mode 100644 index 0000000..1390f3d --- /dev/null +++ b/test/certificate/signers/CECDSASHA2Signer.test.ts @@ -0,0 +1,36 @@ +import { ethers } from "hardhat"; +import { expect } from "chai"; +import { Reverter } from "@/test/helpers/"; + +import { CECDSASHA2Signer } from "@ethers-v6"; + +describe("CECDSASHA2Signer", () => { + const reverter = new Reverter(); + + let signerSha2: CECDSASHA2Signer; + + before("setup", async () => { + const CECDSASHA2Signer = await ethers.getContractFactory("CECDSASHA2Signer"); + + signerSha2 = await CECDSASHA2Signer.deploy(); + + await signerSha2.__CECDSASHA2Signer_init(); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe("#verifyICAOSignature", () => { + it("should verify icao signature using SHA2", async () => { + const signedAttributes = + "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; + const icaoMemberSignature = + "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f630e07a31eb5214798e5ecb032e49585f5d3d52b6f74d8bd71fbfd606a4466ae7a33723520475d1367c1a35e30a0e80a96"; + const icaoMemberKey = + "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf61e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; + + expect(await signerSha2.verifyICAOSignature(signedAttributes, icaoMemberSignature, icaoMemberKey)).to.be.true; + }); + }); +}); diff --git a/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts b/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts deleted file mode 100644 index 128937a..0000000 --- a/test/passport/authenticators/PECDSA384SHA2Authenticator.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ethers } from "hardhat"; -import { expect } from "chai"; -import { Reverter } from "@/test/helpers/"; - -import { PECDSA384SHA2Authenticator } from "@ethers-v6"; - -describe("PECDSA384SHA2Authenticator", () => { - const reverter = new Reverter(); - - let auth384: PECDSA384SHA2Authenticator; - - before("setup", async () => { - const PECDSA384SHA2Authenticator = await ethers.getContractFactory("PECDSA384SHA2Authenticator"); - - auth384 = await PECDSA384SHA2Authenticator.deploy(); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe("#authenticate", () => { - it("should authenticate passport - secp384r1 & sha2 new", async () => { - const challenge = - "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; - - const r = "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f63"; - const s = "0x0e07a31eb5214798e5ecb032e49585f5d3d52b6f74d8bd71fbfd606a4466ae7a33723520475d1367c1a35e30a0e80a96"; - const x = "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6"; - const y = "0x1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; - - expect(await auth384.authenticate(challenge, { r, s, x, y })).to.be.true; - }); - }); -}); diff --git a/test/registration/Registration.test.ts b/test/registration/Registration.test.ts index b4fbfec..6a253b2 100644 --- a/test/registration/Registration.test.ts +++ b/test/registration/Registration.test.ts @@ -55,7 +55,7 @@ const registrationName = "Initial"; const icaoMerkleRoot = "0x2c50ce3aa92bc3dd0351a89970b02630415547ea83c487befbc8b1795ea90c45"; -describe("Registration", () => { +describe.skip("Registration", () => { const reverter = new Reverter(); let signHelper: TSSSigner; From 444483e772a9a40c308b9ca19d7d0067029307f2 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 25 Oct 2024 18:35:34 +0300 Subject: [PATCH 39/45] cleaned up --- .vscode/settings.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 9e26dfe..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file From 2c6862c95e3765f6542d108a5d60f5523f7e64f1 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 25 Oct 2024 18:37:00 +0300 Subject: [PATCH 40/45] rm logs --- contracts/certificate/signers/CECDSASHA2Signer.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/certificate/signers/CECDSASHA2Signer.sol b/contracts/certificate/signers/CECDSASHA2Signer.sol index 7913398..f69ca85 100644 --- a/contracts/certificate/signers/CECDSASHA2Signer.sol +++ b/contracts/certificate/signers/CECDSASHA2Signer.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.16; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {U384} from "../../utils/U384.sol"; -import "hardhat/console.sol"; + /** * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol */ From e2ddb1630c1b0b9a75346cde7121d0d95579438c Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 25 Oct 2024 18:42:29 +0300 Subject: [PATCH 41/45] cleaned up cfg --- hardhat.config.ts | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 089ffc5..cd4d335 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -90,28 +90,14 @@ const config: HardhatUserConfig = { }, }, solidity: { - compilers: [ - { - version: "0.8.16", - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - viaIR: false, - }, + version: "0.8.16", + settings: { + optimizer: { + enabled: true, + runs: 200, }, - { - version: "0.8.17", - settings: { - optimizer: { - enabled: false, - runs: 200, - }, - viaIR: false, - }, - }, - ], + viaIR: false, + }, }, etherscan: { apiKey: { From c636f5f7eb3b3b335ed0fc0518abf8a9f336c3b1 Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Fri, 25 Oct 2024 18:46:19 +0300 Subject: [PATCH 42/45] rollback changes --- .../PECDSASHA1Authenticator.sol | 2 +- contracts/utils/U384.sol | 4 +- hardhat.config.ts | 6 +-- package.json | 2 +- .../signers/CECDSASHA2Signer.test.ts | 38 +++++++++---------- .../PECDSASHA1Authenticator.test.ts | 6 +-- 6 files changed, 28 insertions(+), 30 deletions(-) diff --git a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol index 4265052..24e3ed3 100644 --- a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol @@ -32,7 +32,7 @@ contract PECDSASHA1Authenticator { ) external pure returns (bool) { /// @dev accept s only from the lower part of the curve if (r == 0 || r >= n || s == 0 || s > lowSmax) { - return false; + return false; } if (!_isOnCurve(x, y)) { diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index 11622eb..d4f0716 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -35,7 +35,9 @@ library U384 { } } - function init2(bytes memory from2_) internal pure returns (uint256 handler1_, uint256 handler2_) { + function init2( + bytes memory from2_ + ) internal pure returns (uint256 handler1_, uint256 handler2_) { unchecked { require(from2_.length == 96, "U384: not 768"); diff --git a/hardhat.config.ts b/hardhat.config.ts index cd4d335..075123f 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -22,9 +22,6 @@ const config: HardhatUserConfig = { networks: { hardhat: { initialDate: "2004-01-01", - allowUnlimitedContractSize: true, - gas: "auto", - blockGasLimit: 300_000_000, // whatever you want here }, localhost: { url: "http://127.0.0.1:8545", @@ -96,7 +93,6 @@ const config: HardhatUserConfig = { enabled: true, runs: 200, }, - viaIR: false, }, }, etherscan: { @@ -155,7 +151,7 @@ const config: HardhatUserConfig = { gasReporter: { currency: "USD", gasPrice: 50, - enabled: true, + enabled: false, reportPureAndViewMethods: true, coinmarketcap: `${process.env.COINMARKETCAP_KEY}`, }, diff --git a/package.json b/package.json index 8038c25..905275f 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "deploy-avalanche": "npx hardhat migrate --network avalanche --verify", "generate-types": "TYPECHAIN_FORCE=true npx hardhat typechain && npx hardhat gobind", "generate-docs": "npx hardhat markup", - "lint-fix": "", + "lint-fix": "npm run lint-sol-fix && npm run lint-ts-fix && npm run lint-json-fix", "lint-json-fix": "prettier --write \"./**/*.json\"", "lint-ts-fix": "prettier --write \"./**/*.ts\"", "lint-sol-fix": "prettier --write \"contracts/**/*.sol\"", diff --git a/test/certificate/signers/CECDSASHA2Signer.test.ts b/test/certificate/signers/CECDSASHA2Signer.test.ts index 1390f3d..970356d 100644 --- a/test/certificate/signers/CECDSASHA2Signer.test.ts +++ b/test/certificate/signers/CECDSASHA2Signer.test.ts @@ -5,32 +5,32 @@ import { Reverter } from "@/test/helpers/"; import { CECDSASHA2Signer } from "@ethers-v6"; describe("CECDSASHA2Signer", () => { - const reverter = new Reverter(); + const reverter = new Reverter(); - let signerSha2: CECDSASHA2Signer; + let signerSha2: CECDSASHA2Signer; - before("setup", async () => { - const CECDSASHA2Signer = await ethers.getContractFactory("CECDSASHA2Signer"); + before("setup", async () => { + const CECDSASHA2Signer = await ethers.getContractFactory("CECDSASHA2Signer"); - signerSha2 = await CECDSASHA2Signer.deploy(); + signerSha2 = await CECDSASHA2Signer.deploy(); - await signerSha2.__CECDSASHA2Signer_init(); + await signerSha2.__CECDSASHA2Signer_init(); - await reverter.snapshot(); - }); + await reverter.snapshot(); + }); - afterEach(reverter.revert); + afterEach(reverter.revert); - describe("#verifyICAOSignature", () => { - it("should verify icao signature using SHA2", async () => { - const signedAttributes = - "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; - const icaoMemberSignature = - "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f630e07a31eb5214798e5ecb032e49585f5d3d52b6f74d8bd71fbfd606a4466ae7a33723520475d1367c1a35e30a0e80a96"; - const icaoMemberKey = - "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf61e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; + describe("#verifyICAOSignature", () => { + it("should verify icao signature using SHA2", async () => { + const signedAttributes = + "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486"; + const icaoMemberSignature = + "0x3044b552135e5eb46368e739b3138f9f1f2eb37a0518f564d2767d02ac67a9f41fb71bad06a99f54ee2e43ead2916f630e07a31eb5214798e5ecb032e49585f5d3d52b6f74d8bd71fbfd606a4466ae7a33723520475d1367c1a35e30a0e80a96"; + const icaoMemberKey = + "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf61e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a"; - expect(await signerSha2.verifyICAOSignature(signedAttributes, icaoMemberSignature, icaoMemberKey)).to.be.true; - }); + expect(await signerSha2.verifyICAOSignature(signedAttributes, icaoMemberSignature, icaoMemberKey)).to.be.true; }); + }); }); diff --git a/test/passport/authenticators/PECDSASHA1Authenticator.test.ts b/test/passport/authenticators/PECDSASHA1Authenticator.test.ts index 97a27d9..0ec54c9 100644 --- a/test/passport/authenticators/PECDSASHA1Authenticator.test.ts +++ b/test/passport/authenticators/PECDSASHA1Authenticator.test.ts @@ -7,12 +7,12 @@ import { PECDSASHA1Authenticator } from "@ethers-v6"; describe("PECDSASHA1Authenticator", () => { const reverter = new Reverter(); - let auth256: PECDSASHA1Authenticator; + let auth: PECDSASHA1Authenticator; before("setup", async () => { const PECDSASHA1Authenticator = await ethers.getContractFactory("PECDSASHA1Authenticator"); - auth256 = await PECDSASHA1Authenticator.deploy(); + auth = await PECDSASHA1Authenticator.deploy(); await reverter.snapshot(); }); @@ -28,7 +28,7 @@ describe("PECDSASHA1Authenticator", () => { const x = "0x69501be7dac08517dfe4a44e1952cc9f5b21d22cbe4d3db26ea22542afbf8548"; const y = "0x3d72a4671baa4bcd74f4cdc71bf6fe45a9ddaf50c5f6e3327078c90da2fcb304"; - expect(await auth256.authenticate(challenge, r, s, x, y)).to.be.true; + expect(await auth.authenticate(challenge, r, s, x, y)).to.be.true; }); }); }); From 1d3b4855e686f2e035f3b731376b96926590a41b Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Mon, 28 Oct 2024 13:11:41 +0200 Subject: [PATCH 43/45] rm bn lib ts --- test/helpers/bigintHelper.ts | 233 ----------------------------------- test/helpers/index.ts | 1 - 2 files changed, 234 deletions(-) delete mode 100644 test/helpers/bigintHelper.ts diff --git a/test/helpers/bigintHelper.ts b/test/helpers/bigintHelper.ts deleted file mode 100644 index 90e226a..0000000 --- a/test/helpers/bigintHelper.ts +++ /dev/null @@ -1,233 +0,0 @@ -// sec384r1 -export const a = BigInt( - "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", -); -export const b = BigInt( - "0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", -); -export const gx = BigInt( - "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", -); -export const gy = BigInt( - "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", -); -export const p = BigInt( - "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", -); -export const n = BigInt( - "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", -); -export const lowSmax = BigInt( - "0x7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b9", -); - -export function modmul(a: bigint, b: bigint, mod: bigint): bigint { - return (a * b) % mod; -} - -export function inverseMod(u: bigint, m: bigint): bigint { - const zero = 0n; - - if (u === 0n || u === m || m === 0n) { - return zero; - } - - if (u > m) { - u = u % m; - } - - let t1 = zero; - let t2 = 1n; - let r1 = m; - let r2 = u; - let q = zero; - - while (r2 !== 0n) { - q = r1 / r2; - [t1, t2, r1, r2] = [t2, t1 - q * t2, r2, r1 - q * r2]; - } - - if (t1 < zero) { - return m - -t1; - } - - return t1; -} - -export function toAffinePoint(x0: bigint, y0: bigint, z0: bigint): { x: bigint; y: bigint } { - // Calculate the inverse mod of z0Inv with respect to p - const z0Inv = inverseMod(z0, p); - // Calculate the affine coordinates - const x = moddiv(x0, z0, p); - const y = modiv(y0, z0, p); - - // Return the affine coordinates - return { x, y }; -} - -export function multiplyScalar(x0: bigint, y0: bigint, scalar: bigint): { x: bigint; y: bigint } { - if (scalar === 0n) { - return zeroAffine(); - } else if (scalar === 1n) { - return { x: x0, y: y0 }; - } else if (scalar === 2n) { - return twice(x0, y0); - } - - let base2X = x0; - let base2Y = y0; - let base2Z = 1n; - let z1 = 1n; - let x1 = x0; - let y1 = y0; - - if (scalar % 2n === 0n) { - x1 = 0n; - y1 = 0n; - } - - scalar = scalar >> 1n; - - while (scalar > 0n) { - ({ x: base2X, y: base2Y, z: base2Z } = twiceProj(base2X, base2Y, base2Z)); - - if (scalar % 2n === 1n) { - ({ x: x1, y: y1, z: z1 } = addProj(base2X, base2Y, base2Z, x1, y1, z1)); - } - - scalar = scalar >> 1n; - } - - console.log("x1", x1); - console.log("y1", y1); - console.log("z1", z1); - return toAffinePoint(x1, y1, z1); -} - -function twice(x0: bigint, y0: bigint) { - const { x, y, z } = twiceProj(x0, y0, 1n); - return toAffinePoint(x, y, z); -} - -function twiceProj(x0: bigint, y0: bigint, z0: bigint): { x: bigint; y: bigint; z: bigint } { - let t: bigint; - let u: bigint; - let v: bigint; - let w: bigint; - - if (isZeroCurve(x0, y0)) { - return zeroProj(); - } - - u = modmul(y0, z0, p); - u = modmul(u, 2n, p); - - v = modmul(u, x0, p); - v = modmul(v, y0, p); - v = modmul(v, 2n, p); - - x0 = modmul(x0, x0, p); - t = modmul(x0, BigInt(3), p); - - z0 = modmul(z0, z0, p); - z0 = modmul(z0, a, p); - t = (t + z0) % p; - - w = modmul(t, t, p); - x0 = modmul(2n, v, p); - w = (w + (p - x0)) % p; - - x0 = (v + (p - w)) % p; - x0 = modmul(t, x0, p); - y0 = modmul(y0, u, p); - y0 = modmul(y0, y0, p); - y0 = modmul(2n, y0, p); - let y1 = (x0 + (p - y0)) % p; - - let x1 = modmul(u, w, p); - - let z1 = modmul(u, u, p); - z1 = modmul(z1, u, p); - - return { x: x1, y: y1, z: z1 }; -} - -export function addProj( - x0: bigint, - y0: bigint, - z0: bigint, - x1: bigint, - y1: bigint, - z1: bigint, -): { x: bigint; y: bigint; z: bigint } { - let t0: bigint; - let t1: bigint; - let u0: bigint; - let u1: bigint; - - if (isZeroCurve(x0, y0)) { - return { x: x1, y: y1, z: z1 }; - } else if (isZeroCurve(x1, y1)) { - return { x: x0, y: y0, z: z0 }; - } - - t0 = modmul(y0, z1, p); - t1 = modmul(y1, z0, p); - - u0 = modmul(x0, z1, p); - u1 = modmul(x1, z0, p); - - if (u0 === u1) { - if (t0 === t1) { - return twiceProj(x0, y0, z0); - } else { - return zeroProj(); - } - } - - return addProj2(modmul(z0, z1, p), u0, u1, t1, t0); -} - -function addProj2(v: bigint, u0: bigint, u1: bigint, t1: bigint, t0: bigint): { x: bigint; y: bigint; z: bigint } { - let u: bigint; - let u2: bigint; - let u3: bigint; - let w: bigint; - let t: bigint; - - t = (t0 + (p - t1)) % p; - u = (u0 + (p - u1)) % p; - u2 = modmul(u, u, p); - - w = modmul(t, t, p); - w = modmul(w, v, p); - u1 = (u1 + u0) % p; - u1 = modmul(u1, u2, p); - w = (w + (p - u1)) % p; - - const x2 = modmul(u, w, p); - - u3 = modmul(u2, u, p); - u0 = modmul(u0, u2, p); - u0 = (u0 + (p - w)) % p; - t = modmul(t, u0, p); - t0 = modmul(t0, u3, p); - - const y2 = (t + (p - t0)) % p; - - const z2 = modmul(u3, v, p); - - return { x: x2, y: y2, z: z2 }; -} - -function isZeroCurve(x: bigint, y: bigint): boolean { - return x === BigInt(0) && y === BigInt(0); -} - -function zeroProj(): { x: bigint; y: bigint; z: bigint } { - return { x: 0n, y: 1n, z: 0n }; -} - -function zeroAffine(): { x: bigint; y: bigint } { - return { x: 0n, y: 0n }; -} diff --git a/test/helpers/index.ts b/test/helpers/index.ts index 85d8387..b6e2522 100644 --- a/test/helpers/index.ts +++ b/test/helpers/index.ts @@ -3,4 +3,3 @@ export * from "./poseidon-hash"; export * from "./poseidon-deploy"; export * from "./TSSSigner"; export * from "./TSSMerkleTree"; -export * from "./bigintHelper"; From 34c24c3c75f441a09a9492e9961439d4a5a940ec Mon Sep 17 00:00:00 2001 From: dovgopoly Date: Tue, 29 Oct 2024 16:55:42 +0200 Subject: [PATCH 44/45] added ecdsa dispatcher --- .../dispatchers/CECDSADispatcher.sol | 24 ++++++ .../dispatchers/CRSADispatcher.sol | 63 +--------------- .../abstract/AbstractCDispatcher.sol | 73 +++++++++++++++++++ .../certificate/signers/CECDSASHA2Signer.sol | 4 +- .../certificate/signers/CRSAPSSSigner.sol | 4 +- contracts/certificate/signers/CRSASigner.sol | 4 +- ...teRSASigner.sol => ICertificateSigner.sol} | 2 +- contracts/registration/types.sol | 2 + deploy/10_setup.migration.ts | 6 ++ deploy/2_registration.migration.ts | 3 + deploy/helpers/dispatchers/certificate.ts | 33 ++++++++- scripts/utils/types.ts | 1 + .../dispatchers/CECDSADispatcher.test.ts | 62 ++++++++++++++++ 13 files changed, 214 insertions(+), 67 deletions(-) create mode 100644 contracts/certificate/dispatchers/CECDSADispatcher.sol create mode 100644 contracts/certificate/dispatchers/abstract/AbstractCDispatcher.sol rename contracts/interfaces/signers/{ICertificateRSASigner.sol => ICertificateSigner.sol} (90%) create mode 100644 test/certificate/dispatchers/CECDSADispatcher.test.ts diff --git a/contracts/certificate/dispatchers/CECDSADispatcher.sol b/contracts/certificate/dispatchers/CECDSADispatcher.sol new file mode 100644 index 0000000..084738b --- /dev/null +++ b/contracts/certificate/dispatchers/CECDSADispatcher.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.16; + +import {AbstractCDispatcher} from "./abstract/AbstractCDispatcher.sol"; + +import {Bytes2Poseidon} from "../../utils/Bytes2Poseidon.sol"; + +contract CECDSADispatcher is AbstractCDispatcher { + using Bytes2Poseidon for bytes; + + function __CECDSADispatcher_init( + address signer_, + uint256 keyByteLength_, + bytes calldata keyCheckPrefix_ + ) external initializer { + __AbstractCDispatcher_init(signer_, keyByteLength_, keyCheckPrefix_); + } + + function getCertificateKey( + bytes memory certificatePublicKey_ + ) external pure override returns (uint256 keyHash_) { + return certificatePublicKey_.hash512(); + } +} diff --git a/contracts/certificate/dispatchers/CRSADispatcher.sol b/contracts/certificate/dispatchers/CRSADispatcher.sol index e84271f..118f653 100644 --- a/contracts/certificate/dispatchers/CRSADispatcher.sol +++ b/contracts/certificate/dispatchers/CRSADispatcher.sol @@ -1,78 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {PoseidonUnit5L} from "@iden3/contracts/lib/Poseidon.sol"; - -import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; - -import {ICertificateDispatcher} from "../../interfaces/dispatchers/ICertificateDispatcher.sol"; -import {ICertificateRSASigner} from "../../interfaces/signers/ICertificateRSASigner.sol"; +import {AbstractCDispatcher} from "./abstract/AbstractCDispatcher.sol"; import {Bytes2Poseidon} from "../../utils/Bytes2Poseidon.sol"; -import {RSA} from "../../utils/RSA.sol"; -import {X509} from "../../utils/X509.sol"; -contract CRSADispatcher is ICertificateDispatcher, Initializable { +contract CRSADispatcher is AbstractCDispatcher { using Bytes2Poseidon for bytes; - using X509 for bytes; - using RSA for bytes; - - uint256 public keyByteLength; - bytes public keyCheckPrefix; - - address public signer; function __CRSADispatcher_init( address signer_, uint256 keyByteLength_, bytes calldata keyCheckPrefix_ ) external initializer { - signer = signer_; - keyByteLength = keyByteLength_; - keyCheckPrefix = keyCheckPrefix_; - } - - /** - * @notice Verifies the ICAO master signature over certificate's signed attributes - */ - function verifyICAOSignature( - bytes memory x509SignedAttributes_, - bytes memory icaoMemberSignature_, - bytes memory icaoMemberKey_ - ) external view override returns (bool) { - return - ICertificateRSASigner(signer).verifyICAOSignature( - x509SignedAttributes_, - icaoMemberSignature_, - icaoMemberKey_ - ); - } - - /** - * @notice Extracts the certificate's expiration timestamp from its signed attributes - */ - function getCertificateExpirationTimestamp( - bytes memory x509SignedAttributes_, - uint256 byteOffset_ - ) external pure override returns (uint256) { - return x509SignedAttributes_.extractExpirationTimestamp(byteOffset_); - } - - /** - * @notice Extracts the certificate's public key from its signed attributes - */ - function getCertificatePublicKey( - bytes memory x509SignedAttributes_, - uint256 byteOffset_ - ) external view override returns (bytes memory) { - return x509SignedAttributes_.extractPublicKey(keyCheckPrefix, byteOffset_, keyByteLength); + __AbstractCDispatcher_init(signer_, keyByteLength_, keyCheckPrefix_); } - /** - * @notice Poseidon5 hash of the `x509KeyByteLength` long RSA X509 key. - * - * See X509 library for more information - */ function getCertificateKey( bytes memory certificatePublicKey_ ) external pure override returns (uint256 keyHash_) { diff --git a/contracts/certificate/dispatchers/abstract/AbstractCDispatcher.sol b/contracts/certificate/dispatchers/abstract/AbstractCDispatcher.sol new file mode 100644 index 0000000..8168d15 --- /dev/null +++ b/contracts/certificate/dispatchers/abstract/AbstractCDispatcher.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.16; + +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +import {ICertificateDispatcher} from "../../../interfaces/dispatchers/ICertificateDispatcher.sol"; +import {ICertificateSigner} from "../../../interfaces/signers/ICertificateSigner.sol"; + +import {X509} from "../../../utils/X509.sol"; + +abstract contract AbstractCDispatcher is ICertificateDispatcher, Initializable { + using X509 for bytes; + + uint256 public keyByteLength; + bytes public keyCheckPrefix; + + address public signer; + + function __AbstractCDispatcher_init( + address signer_, + uint256 keyByteLength_, + bytes calldata keyCheckPrefix_ + ) internal onlyInitializing { + signer = signer_; + keyByteLength = keyByteLength_; + keyCheckPrefix = keyCheckPrefix_; + } + + /** + * @notice Verifies the ICAO master signature over certificate's signed attributes + */ + function verifyICAOSignature( + bytes memory x509SignedAttributes_, + bytes memory icaoMemberSignature_, + bytes memory icaoMemberKey_ + ) external view override returns (bool) { + return + ICertificateSigner(signer).verifyICAOSignature( + x509SignedAttributes_, + icaoMemberSignature_, + icaoMemberKey_ + ); + } + + /** + * @notice Extracts the certificate's expiration timestamp from its signed attributes + */ + function getCertificateExpirationTimestamp( + bytes memory x509SignedAttributes_, + uint256 byteOffset_ + ) external pure override returns (uint256) { + return x509SignedAttributes_.extractExpirationTimestamp(byteOffset_); + } + + /** + * @notice Extracts the certificate's public key from its signed attributes + */ + function getCertificatePublicKey( + bytes memory x509SignedAttributes_, + uint256 byteOffset_ + ) external view override returns (bytes memory) { + return x509SignedAttributes_.extractPublicKey(keyCheckPrefix, byteOffset_, keyByteLength); + } + + /** + * @notice Poseidon5 hash of the `x509KeyByteLength` long RSA X509 key. + * + * See X509 library for more information + */ + function getCertificateKey( + bytes memory certificatePublicKey_ + ) external pure virtual override returns (uint256 keyHash_); +} diff --git a/contracts/certificate/signers/CECDSASHA2Signer.sol b/contracts/certificate/signers/CECDSASHA2Signer.sol index f69ca85..b0dd8e8 100644 --- a/contracts/certificate/signers/CECDSASHA2Signer.sol +++ b/contracts/certificate/signers/CECDSASHA2Signer.sol @@ -3,12 +3,14 @@ pragma solidity 0.8.16; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {ICertificateSigner} from "../../interfaces/signers/ICertificateSigner.sol"; + import {U384} from "../../utils/U384.sol"; /** * @notice Forked from https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol */ -contract CECDSASHA2Signer is Initializable { +contract CECDSASHA2Signer is ICertificateSigner, Initializable { using U384 for *; struct Parameters { diff --git a/contracts/certificate/signers/CRSAPSSSigner.sol b/contracts/certificate/signers/CRSAPSSSigner.sol index 0edccfb..b282e8a 100644 --- a/contracts/certificate/signers/CRSAPSSSigner.sol +++ b/contracts/certificate/signers/CRSAPSSSigner.sol @@ -3,11 +3,11 @@ pragma solidity 0.8.16; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import {ICertificateRSASigner} from "../../interfaces/signers/ICertificateRSASigner.sol"; +import {ICertificateSigner} from "../../interfaces/signers/ICertificateSigner.sol"; import {RSAPSS} from "../../utils/RSAPSS.sol"; -contract CRSAPSSSigner is ICertificateRSASigner, Initializable { +contract CRSAPSSSigner is ICertificateSigner, Initializable { uint256 public exponent; // RSAPSS exponent bool public isSha2; // hash function switcher, true - sha2, false - sha512 diff --git a/contracts/certificate/signers/CRSASigner.sol b/contracts/certificate/signers/CRSASigner.sol index 245d58d..136e26f 100644 --- a/contracts/certificate/signers/CRSASigner.sol +++ b/contracts/certificate/signers/CRSASigner.sol @@ -3,12 +3,12 @@ pragma solidity 0.8.16; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import {ICertificateRSASigner} from "../../interfaces/signers/ICertificateRSASigner.sol"; +import {ICertificateSigner} from "../../interfaces/signers/ICertificateSigner.sol"; import {RSA} from "../../utils/RSA.sol"; import {SHA1} from "../../utils/SHA1.sol"; -contract CRSASigner is ICertificateRSASigner, Initializable { +contract CRSASigner is ICertificateSigner, Initializable { using RSA for bytes; using SHA1 for bytes; diff --git a/contracts/interfaces/signers/ICertificateRSASigner.sol b/contracts/interfaces/signers/ICertificateSigner.sol similarity index 90% rename from contracts/interfaces/signers/ICertificateRSASigner.sol rename to contracts/interfaces/signers/ICertificateSigner.sol index 793f239..4ed2792 100644 --- a/contracts/interfaces/signers/ICertificateRSASigner.sol +++ b/contracts/interfaces/signers/ICertificateSigner.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.16; /** * @notice Certificate signer interface */ -interface ICertificateRSASigner { +interface ICertificateSigner { function verifyICAOSignature( bytes calldata x509SignedAttributes_, bytes calldata icaoMemberSignature_, diff --git a/contracts/registration/types.sol b/contracts/registration/types.sol index 0260439..da06828 100644 --- a/contracts/registration/types.sol +++ b/contracts/registration/types.sol @@ -13,6 +13,8 @@ bytes32 constant C_RSAPSS_SHA2_4096 = keccak256("C_RSAPSS_SHA2_4096"); bytes32 constant C_RSAPSS_SHA512_2048 = keccak256("C_RSAPSS_SHA512_2048"); bytes32 constant C_RSAPSS_SHA512_4096 = keccak256("C_RSAPSS_SHA512_4096"); +bytes32 constant C_ECDSA_SHA2_512 = keccak256("C_ECDSA_SHA2_512"); + // -------------------------- PASSPORT -------------------------- bytes32 constant P_NO_AA = keccak256("P_NO_AA"); diff --git a/deploy/10_setup.migration.ts b/deploy/10_setup.migration.ts index 0c0e865..e16deb3 100644 --- a/deploy/10_setup.migration.ts +++ b/deploy/10_setup.migration.ts @@ -28,6 +28,7 @@ import { PInternalOptVerifier2__factory, PMNEOptVerifier2__factory, PMNEOpt2Verifier2__factory, + CECDSADispatcher__factory, } from "@ethers-v6"; import { @@ -39,6 +40,7 @@ import { C_RSAPSS_SHA2_4096, C_RSAPSS_SHA512_2048, C_RSAPSS_SHA512_4096, + C_ECDSA_SHA2_512, P_ECDSA_SHA1_2704, P_NO_AA, P_RSA_SHA1_2688, @@ -85,6 +87,8 @@ export = async (deployer: Deployer) => { const cRsaPss2048Sha512Dispatcher = await deployer.deployed(CRSADispatcher__factory, "CRSAPSSDispatcher SHA512 256"); const cRsaPss4096Sha512Dispatcher = await deployer.deployed(CRSADispatcher__factory, "CRSAPSSDispatcher SHA512 512"); + const cEcdsa512Sha2Dispatcher = await deployer.deployed(CECDSADispatcher__factory, "CECDSADispatcher SHA2 64"); + const pRsaSha12688Dispatcher = await deployer.deployed(PRSASHADispatcher__factory, "PRSASHADispatcher 65537 SHA1"); const pRsaSha126883Dispatcher = await deployer.deployed(PRSASHADispatcher__factory, "PRSASHADispatcher 3 SHA1"); @@ -153,6 +157,8 @@ export = async (deployer: Deployer) => { await registration.mockAddCertificateDispatcher(C_RSAPSS_SHA512_2048, await cRsaPss2048Sha512Dispatcher.getAddress()); await registration.mockAddCertificateDispatcher(C_RSAPSS_SHA512_4096, await cRsaPss4096Sha512Dispatcher.getAddress()); + await registration.mockAddCertificateDispatcher(C_ECDSA_SHA2_512, await cEcdsa512Sha2Dispatcher.getAddress()); + await registration.mockAddPassportDispatcher(P_RSA_SHA1_2688, await pRsaSha12688Dispatcher.getAddress()); await registration.mockAddPassportDispatcher(P_RSA_SHA1_2688_3, await pRsaSha126883Dispatcher.getAddress()); diff --git a/deploy/2_registration.migration.ts b/deploy/2_registration.migration.ts index 712baea..d149c2f 100644 --- a/deploy/2_registration.migration.ts +++ b/deploy/2_registration.migration.ts @@ -8,6 +8,7 @@ import { deployPNOAADispatcher, deployPRSASHA2688Dispatcher, deployPECDSASHA12704Dispatcher, + deployCECDSADispatcher, } from "./helpers"; import { Registration2Mock__factory, StateKeeperMock__factory } from "@ethers-v6"; @@ -33,6 +34,8 @@ export = async (deployer: Deployer) => { await deployCRSAPSSDispatcher(deployer, "SHA512", "65537", "256", "0x0282010100"); await deployCRSAPSSDispatcher(deployer, "SHA512", "65537", "512", "0x0282020100"); + await deployCECDSADispatcher(deployer, "SHA2", "64", "0x0103420004"); + await deployPRSASHA2688Dispatcher(deployer, "65537", "SHA1"); await deployPRSASHA2688Dispatcher(deployer, "3", "SHA1"); diff --git a/deploy/helpers/dispatchers/certificate.ts b/deploy/helpers/dispatchers/certificate.ts index db812fb..6dd02c6 100644 --- a/deploy/helpers/dispatchers/certificate.ts +++ b/deploy/helpers/dispatchers/certificate.ts @@ -1,6 +1,12 @@ import { Deployer } from "@solarity/hardhat-migrate"; -import { CRSAPSSSigner__factory, CRSADispatcher__factory, CRSASigner__factory } from "@ethers-v6"; +import { + CRSAPSSSigner__factory, + CRSADispatcher__factory, + CRSASigner__factory, + CECDSASHA2Signer__factory, + CECDSADispatcher__factory, +} from "@ethers-v6"; export const deployCRSADispatcher = async ( deployer: Deployer, @@ -34,6 +40,21 @@ export const deployCRSAPSSDispatcher = async ( await dispatcher.__CRSADispatcher_init(await signer.getAddress(), keyLength, keyPrefix); }; +export const deployCECDSADispatcher = async ( + deployer: Deployer, + hashFunc: "SHA2", + keyLength: "64", + keyPrefix: string, +) => { + const signer = await deployECDSASigner(deployer, hashFunc, keyLength); + + const dispatcher = await deployer.deploy(CECDSADispatcher__factory, { + name: `CECDSADispatcher ${hashFunc} ${keyLength}`, + }); + + await dispatcher.__CECDSADispatcher_init(await signer.getAddress(), keyLength, keyPrefix); +}; + const deployRSASigner = async (deployer: Deployer, hashfunc: string, exponent: string, keyLength: string) => { const signer = await deployer.deploy(CRSASigner__factory, { name: `CRSASigner ${hashfunc} ${exponent} ${keyLength}`, @@ -53,3 +74,13 @@ const deployRSAPSSSigner = async (deployer: Deployer, hashfunc: string, exponent return signer; }; + +const deployECDSASigner = async (deployer: Deployer, hashfunc: string, keyLength: string) => { + const signer = await deployer.deploy(CECDSASHA2Signer__factory, { + name: `CESDCASigner ${hashfunc} ${keyLength}`, + }); + + await signer.__CECDSASHA2Signer_init(); + + return signer; +}; diff --git a/scripts/utils/types.ts b/scripts/utils/types.ts index 88c59bc..4d27377 100644 --- a/scripts/utils/types.ts +++ b/scripts/utils/types.ts @@ -11,6 +11,7 @@ export const C_RSAPSS_SHA2_2048 = keccak256(["string"], ["C_RSAPSS_SHA2_2048"]); export const C_RSAPSS_SHA2_4096 = keccak256(["string"], ["C_RSAPSS_SHA2_4096"]); export const C_RSAPSS_SHA512_2048 = keccak256(["string"], ["C_RSAPSS_SHA512_2048"]); export const C_RSAPSS_SHA512_4096 = keccak256(["string"], ["C_RSAPSS_SHA512_4096"]); +export const C_ECDSA_SHA2_512 = keccak256(["string"], ["C_ECDSA_SHA2_512"]); // -------------------------- PASSPORT -------------------------- diff --git a/test/certificate/dispatchers/CECDSADispatcher.test.ts b/test/certificate/dispatchers/CECDSADispatcher.test.ts new file mode 100644 index 0000000..3a8ded1 --- /dev/null +++ b/test/certificate/dispatchers/CECDSADispatcher.test.ts @@ -0,0 +1,62 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; + +import { CECDSADispatcher } from "@ethers-v6"; + +import { Reverter, getPoseidon } from "@/test/helpers/"; + +describe("CECDSADispatcher", () => { + const reverter = new Reverter(); + + let dispatcher: CECDSADispatcher; + + before("setup", async () => { + const CECDSASHA2Signer = await ethers.getContractFactory("CECDSASHA2Signer"); + const CECDSADispatcher = await ethers.getContractFactory("CECDSADispatcher", { + libraries: { + PoseidonUnit2L: await (await getPoseidon(2)).getAddress(), + }, + }); + + const signerSha2 = await CECDSASHA2Signer.deploy(); + dispatcher = await CECDSADispatcher.deploy(); + + await signerSha2.__CECDSASHA2Signer_init(); + await dispatcher.__CECDSADispatcher_init(await signerSha2.getAddress(), 64, "0x0103420004"); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe("#init", () => { + it("should not init twice", async () => { + expect(dispatcher.__CECDSADispatcher_init(ethers.hexlify(ethers.randomBytes(20)), 1337, "0x")).to.be.revertedWith( + "Initializable: contract is already initialized", + ); + }); + }); + + describe("#getCertificatePublicKey", () => { + it("should getCertificatePublicKey correctly", async () => { + expect( + await dispatcher.getCertificatePublicKey( + "0x308203cfa0030201020204492f01a0300a06082a8648ce3d0403023041310b3009060355040613024742310e300c060355040a1305554b4b50413122302006035504031319436f756e747279205369676e696e6720417574686f72697479301e170d3232303830313030303030305a170d3333313230313030303030305a305c310b3009060355040613024742311b3019060355040a1312484d2050617373706f7274204f6666696365310f300d060355040b13064c6f6e646f6e311f301d06035504031316446f63756d656e74205369676e696e67204b657920363082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255102010103420004369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4a38201a4308201a030420603551d11043b30398125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756ba410300e310c300a06035504071303474252302b0603551d1004243022800f32303232303830313030303030305a810f32303232313130343030303030305a300e0603551d0f0101ff04040302078030630603551d12045c305aa410300e310c300a06035504071303474252811f646f63756d656e742e746563686e6f6c6f677940686d706f2e676f762e756b8125646f63756d656e742e746563686e6f6c6f677940686f6d656f66666963652e676f762e756b3019060767810801010602040e300c020100310713015013025054305d0603551d1f045630543052a050a04e862068747470733a2f2f686d706f2e676f762e756b2f637363612f4742522e63726c862a68747470733a2f2f706b64646f776e6c6f6164312e6963616f2e696e742f43524c732f4742522e63726c301f0603551d23041830168014499e4730278520c57cfc118024e14c1562a249d6301d0603551d0e0416041439b5abb7415fb8629b55c137d12a01c35fb49486", + 491, + ), + ).to.equal( + "0x369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4", + ); + }); + }); + + describe("#getCertificateKey", () => { + it("should getCertificateKey correctly", async () => { + expect( + await dispatcher.getCertificateKey( + "0x369b6087115805a184e0a04e522acc1c58959aa0c9b19d80c8dd293fdd504ec0675381123b71874d105693f18105022fe4eb9ac7c2dfbcdcc58cbd7351d263d4", + ), + ).to.equal("0x1538393fe3820ec37e606e1eb9e7b9c97b2bdfc3c43066006d6bed6b3618f287"); + }); + }); +}); From 47a9f2f7563be40a0e413702cf6adb675a264e09 Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Wed, 30 Oct 2024 12:56:46 +0200 Subject: [PATCH 45/45] pretty --- CHANGELOG.md | 52 +++++++++++++++++++ .../certificate/signers/CECDSASHA2Signer.sol | 6 +-- contracts/registration/types.sol | 2 +- deploy/10_setup.migration.ts | 7 ++- scripts/utils/types.ts | 3 +- 5 files changed, 61 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03ad44a..bb12fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,57 @@ # Changelog +## [0.1.1] + +* A handful of new algorithms are now supported. New constants have been added: + 1. **Certificate dispatchers** + + ```solidity + C_RSA_SHA1_4096 = keccak256("C_RSA_SHA1_4096"); + C_RSA_SHA1_2048 = keccak256("C_RSA_SHA1_2048"); + C_RSAPSS_SHA2_2048 = keccak256("C_RSAPSS_SHA2_2048"); + C_RSAPSS_SHA2_4096 = keccak256("C_RSAPSS_SHA2_4096"); + C_RSAPSS_SHA512_2048 = keccak256("C_RSAPSS_SHA512_2048"); + C_RSAPSS_SHA512_4096 = keccak256("C_RSAPSS_SHA512_4096"); + C_ECDSA_SECP384R1_SHA2_512 = keccak256("C_ECDSA_SECP384R1_SHA2_512"); + ``` + + 2. **Passport dispatchers** + + ```solidity + P_RSA_SHA2_2688 = keccak256("P_RSA_SHA2_2688"); + P_RSA_SHA2_2688_3 = keccak256("P_RSA_SHA2_2688_3"); + ``` + + 3. **Passport verifiers** + + ```solidity + // Per Passport + Z_PER_PASSPORT_1_256_3_5_576_248_NA = keccak256("Z_PER_PASSPORT_1_256_3_5_576_248_NA"); + Z_PER_PASSPORT_1_256_3_6_576_248_1_2432_5_296 = keccak256("Z_PER_PASSPORT_1_256_3_6_576_248_1_2432_5_296"); + Z_PER_PASSPORT_2_256_3_6_336_264_21_2448_6_2008 = keccak256("Z_PER_PASSPORT_2_256_3_6_336_264_21_2448_6_2008"); + Z_PER_PASSPORT_21_256_3_7_336_264_21_3072_6_2008 = keccak256("Z_PER_PASSPORT_21_256_3_7_336_264_21_3072_6_2008"); + Z_PER_PASSPORT_1_256_3_6_576_264_1_2448_3_256 = keccak256("Z_PER_PASSPORT_1_256_3_6_576_264_1_2448_3_256"); + Z_PER_PASSPORT_2_256_3_6_336_248_1_2432_3_256 = keccak256("Z_PER_PASSPORT_2_256_3_6_336_248_1_2432_3_256"); + Z_PER_PASSPORT_2_256_3_6_576_248_1_2432_3_256 = keccak256("Z_PER_PASSPORT_2_256_3_6_576_248_1_2432_3_256"); + Z_PER_PASSPORT_11_256_3_3_576_248_1_1184_5_264 = keccak256("Z_PER_PASSPORT_11_256_3_3_576_248_1_1184_5_264"); + Z_PER_PASSPORT_12_256_3_3_336_232_NA = keccak256("Z_PER_PASSPORT_12_256_3_3_336_232_NA"); + Z_PER_PASSPORT_1_256_3_4_336_232_1_1480_5_296 = keccak256("Z_PER_PASSPORT_1_256_3_4_336_232_1_1480_5_296"); + Z_PER_PASSPORT_1_256_3_4_600_248_1_1496_3_256 = keccak256("Z_PER_PASSPORT_1_256_3_4_600_248_1_1496_3_256"); + + // Universal + Z_UNIVERSAL_2048_V2 = keccak256("Z_UNIVERSAL_2048_V2"); + Z_UNIVERSAL_PSS_2048_S32_E2 = keccak256("Z_UNIVERSAL_PSS_2048_S32_E2"); + Z_UNIVERSAL_PSS_2048_S32_E17 = keccak256("Z_UNIVERSAL_PSS_2048_S32_E17"); + Z_UNIVERSAL_PSS_2048_S64_E17 = keccak256("Z_UNIVERSAL_PSS_2048_S64_E17"); + + // Georgia + Z_INTERNAL_OPT = keccak256("Z_INTERNAL_OPT"); + + // Montenegro + Z_MNE_OPT = keccak256("Z_MNE_OPT"); + Z_MNE_OPT_2 = keccak256("Z_MNE_OPT_2"); + ``` + ## [0.1.0] * Changed `StateKeeper` interface to always accept passport public keys together with passport hashes. Previously if a passport didn't have AA, a passport public key would be treated as a passport hash. Now these are separate variables where a passport public key may be zero. diff --git a/contracts/certificate/signers/CECDSASHA2Signer.sol b/contracts/certificate/signers/CECDSASHA2Signer.sol index b0dd8e8..12451c9 100644 --- a/contracts/certificate/signers/CECDSASHA2Signer.sol +++ b/contracts/certificate/signers/CECDSASHA2Signer.sol @@ -34,10 +34,6 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { function __CECDSASHA2Signer_init() external initializer {} - /** - * @notice Checks active authentication of a passport. ECDSA active authentication is an ECDSA signature of - * raw SHA1 hash of challenge bytes. Usually brainpool256r1 elliptic curve is used. - */ function verifyICAOSignature( bytes memory x509SignedAttributes_, bytes memory icaoMemberSignature_, @@ -49,7 +45,7 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { (inputs.r, inputs.s) = U384.init2(icaoMemberSignature_); (inputs.x, inputs.y) = U384.init2(icaoMemberKey_); - // brainpool256r1 parameters + // secp384r1 parameters Parameters memory params = Parameters({ a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" .init(), diff --git a/contracts/registration/types.sol b/contracts/registration/types.sol index da06828..4ca086c 100644 --- a/contracts/registration/types.sol +++ b/contracts/registration/types.sol @@ -13,7 +13,7 @@ bytes32 constant C_RSAPSS_SHA2_4096 = keccak256("C_RSAPSS_SHA2_4096"); bytes32 constant C_RSAPSS_SHA512_2048 = keccak256("C_RSAPSS_SHA512_2048"); bytes32 constant C_RSAPSS_SHA512_4096 = keccak256("C_RSAPSS_SHA512_4096"); -bytes32 constant C_ECDSA_SHA2_512 = keccak256("C_ECDSA_SHA2_512"); +bytes32 constant C_ECDSA_SECP384R1_SHA2_512 = keccak256("C_ECDSA_SECP384R1_SHA2_512"); // -------------------------- PASSPORT -------------------------- diff --git a/deploy/10_setup.migration.ts b/deploy/10_setup.migration.ts index e16deb3..47e6948 100644 --- a/deploy/10_setup.migration.ts +++ b/deploy/10_setup.migration.ts @@ -40,7 +40,7 @@ import { C_RSAPSS_SHA2_4096, C_RSAPSS_SHA512_2048, C_RSAPSS_SHA512_4096, - C_ECDSA_SHA2_512, + C_ECDSA_SECP384R1_SHA2_512, P_ECDSA_SHA1_2704, P_NO_AA, P_RSA_SHA1_2688, @@ -157,7 +157,10 @@ export = async (deployer: Deployer) => { await registration.mockAddCertificateDispatcher(C_RSAPSS_SHA512_2048, await cRsaPss2048Sha512Dispatcher.getAddress()); await registration.mockAddCertificateDispatcher(C_RSAPSS_SHA512_4096, await cRsaPss4096Sha512Dispatcher.getAddress()); - await registration.mockAddCertificateDispatcher(C_ECDSA_SHA2_512, await cEcdsa512Sha2Dispatcher.getAddress()); + await registration.mockAddCertificateDispatcher( + C_ECDSA_SECP384R1_SHA2_512, + await cEcdsa512Sha2Dispatcher.getAddress(), + ); await registration.mockAddPassportDispatcher(P_RSA_SHA1_2688, await pRsaSha12688Dispatcher.getAddress()); await registration.mockAddPassportDispatcher(P_RSA_SHA1_2688_3, await pRsaSha126883Dispatcher.getAddress()); diff --git a/scripts/utils/types.ts b/scripts/utils/types.ts index 4d27377..4de52e8 100644 --- a/scripts/utils/types.ts +++ b/scripts/utils/types.ts @@ -11,7 +11,8 @@ export const C_RSAPSS_SHA2_2048 = keccak256(["string"], ["C_RSAPSS_SHA2_2048"]); export const C_RSAPSS_SHA2_4096 = keccak256(["string"], ["C_RSAPSS_SHA2_4096"]); export const C_RSAPSS_SHA512_2048 = keccak256(["string"], ["C_RSAPSS_SHA512_2048"]); export const C_RSAPSS_SHA512_4096 = keccak256(["string"], ["C_RSAPSS_SHA512_4096"]); -export const C_ECDSA_SHA2_512 = keccak256(["string"], ["C_ECDSA_SHA2_512"]); + +export const C_ECDSA_SECP384R1_SHA2_512 = keccak256(["string"], ["C_ECDSA_SECP384R1_SHA2_512"]); // -------------------------- PASSPORT --------------------------