From c3c0d89c9bc2b1aaf8f5b12fad57b97f61fbb3ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E6=9D=91=E9=BE=8D=E7=9F=A2?= Date: Tue, 22 Jan 2019 09:41:45 +0900 Subject: [PATCH 1/6] Copied code at commit f60e238c --- contracts/bigint/BigInt.vy | 182 +++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 contracts/bigint/BigInt.vy diff --git a/contracts/bigint/BigInt.vy b/contracts/bigint/BigInt.vy new file mode 100644 index 0000000..5add6ef --- /dev/null +++ b/contracts/bigint/BigInt.vy @@ -0,0 +1,182 @@ +# @dev RSA Accumulator +# @author Ryuya Nakamura (@nrryuya) +# Based on The Matter team's work: +# https://github.com/matterinc/RSAAccumulator/blob/master/contracts/RSAAccumulator.sol + +### CONSTANTS ### +# FIXME: The sizes of arrays in this file should be replaced with these constants: +# https://github.com/ethereum/vyper/issues/1167 + +N_LIMBS_LENGTH: constant(int128) = 8 +G: constant(uint256) = 3 + +M_LIST_LENGTH: constant(int128) = N_LIMBS_LENGTH +M_BYTE_COUNT: constant(int128) = 32 * M_LIST_LENGTH +M_BYTE_COUNT_BYTES32: constant(bytes32) = convert(M_BYTE_COUNT, bytes32) +# For now, the same lengths are used for the simplicity of impelementation. +BASE_BYTE_COUNT_BYTES32: constant(bytes32) = M_BYTE_COUNT_BYTES32 +E_BYTE_COUNT_BYTES32: constant(bytes32) = M_BYTE_COUNT_BYTES32 + +PRECOMPILED_BIGMODEXP: constant(address) = 0x0000000000000000000000000000000000000005 + + +### BIG INTEGER ARITHMETIC FUNCTIONS ### + +# this assumes that exponent in never larger than 256 bits +@private +def _modularExp(_base: uint256[8], _e: uint256, _m: uint256[8]) -> uint256[8]: + e: uint256[8] + e[M_LIST_LENGTH - 1] = _e + + tmp: bytes32[8] + for i in range(M_LIST_LENGTH): + tmp[i] = convert(_base[i], bytes32) + base: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + + for i in range(M_LIST_LENGTH): + tmp[i] = convert(e[i], bytes32) + exponent: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + + for i in range(M_LIST_LENGTH): + tmp[i] = convert(_m[i], bytes32) + modulus: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + # ref. https://eips.ethereum.org/EIPS/eip-198 + # 864 = 32 * 3 + + + + data: bytes[864] = concat(BASE_BYTE_COUNT_BYTES32, E_BYTE_COUNT_BYTES32, M_BYTE_COUNT_BYTES32, + base, exponent, modulus) + # NOTE: raw_call doesn't support static call for now. + res: bytes[256] = raw_call(PRECOMPILED_BIGMODEXP, data, outsize=256, gas=2000) + + out: uint256[8] + for i in range(M_LIST_LENGTH): + out[i] = convert(extract32(res, i * 32, type=bytes32), uint256) + return out + + +@private +def _modularExpVariableLength(_base: uint256[8], _e: uint256[8], _m: uint256[8]) -> uint256[8]: + tmp: bytes32[8] + for i in range(M_LIST_LENGTH): + tmp[i] = convert(_base[i], bytes32) + base: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + + for i in range(M_LIST_LENGTH): + tmp[i] = convert(_e[i], bytes32) + exponent: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + + for i in range(M_LIST_LENGTH): + tmp[i] = convert(_m[i], bytes32) + modulus: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + # ref. https://eips.ethereum.org/EIPS/eip-198 + # 864 = 32 * 3 + + + + data: bytes[864] = concat(BASE_BYTE_COUNT_BYTES32, E_BYTE_COUNT_BYTES32, M_BYTE_COUNT_BYTES32, + base, exponent, modulus) + # NOTE: raw_call doesn't support static call for now. + res: bytes[256] = raw_call(PRECOMPILED_BIGMODEXP, data, outsize=256, gas=2000) + + out: uint256[8] + for i in range(M_LIST_LENGTH): + out[i] = convert(extract32(res, i * 32, type=bytes32), uint256) + return out + + +@private +@constant +def _wrappingSub(_a: uint256[8], _b: uint256[8]) -> uint256[8]: + borrow: bool = False + limb: uint256 = 0 + o: uint256[8] + for i in range(M_LIST_LENGTH): + j: int128 = M_LIST_LENGTH - i + limb = _a[j] + if borrow: + if limb == 0: + borrow = True + limb -= 1 + o[j] = limb - _b[j] + else: + limb -= 1 + if limb >= _b[j]: + borrow = False + o[j] = limb - _b[j] + else: + if limb < _b[j]: + borrow = True + o[j] = limb - _b[j] + return o + +@private +@constant +def _wrappingAdd(_a: uint256[8], _b: uint256[8]) -> uint256[8]: + carry: bool = False + limb: uint256 = 0 + subaddition: uint256 = 0 + o: uint256[8] + for i in range(M_LIST_LENGTH): + j: int128 = M_LIST_LENGTH - i + limb = _a[j] + if carry: + if limb == 0: + carry = True + o[j] = _b[j] + else: + limb += 1 + subaddition = limb + _b[j] + if subaddition >= limb: + carry = False + o[j] = subaddition + else: + subaddition = limb + _b[j] + if subaddition < limb: + carry = True + o[j] = subaddition + return o + +@private +@constant +def _compare(_a: uint256[8], _b: uint256[8]) -> int128: + for i in range(M_LIST_LENGTH): + if _a[i] > _b[i]: + return 1 + elif _a[i] < _b[i]: + return -1 + return 0 + +@private +@constant +def _modularSub(_a: uint256[8], _b: uint256[8], _m: uint256[8]) -> uint256[8]: + o: uint256[8] + comparison: int128 = self._compare(_a, _b) + if comparison == 0: + return o + elif comparison == 1: + return self._wrappingSub(_a, _b) + else: + tmp: uint256[8] = self._wrappingSub(_b, _a) + return self._wrappingSub(_m, tmp) + +@private +@constant +def _modularAdd(_a: uint256[8], _b: uint256[8], _m: uint256[8]) -> uint256[8]: + space: uint256[8] = self._wrappingSub(_m, _a) + o: uint256[8] + comparison: int128 = self._compare(_a, _b) + if comparison == 0: + return o + elif comparison == 1: + return self._wrappingAdd(_a, _b) + else: + return self._wrappingSub(_b, space) + +@private +def _modularMul4(_a: uint256[8], _b: uint256[8], _m: uint256[8]) -> uint256[8]: + aPlusB: uint256[8] = self._modularExp(self._modularAdd(_a, _b, _m), 2, _m) + aMinusB: uint256[8] = self._modularExp(self._modularSub(_a, _b, _m), 2, _m) + return self._modularSub(aPlusB, aMinusB, _m) + +# cheat and just do two additions +@private +@constant +def _modularMulBy4(_a: uint256[8], _m: uint256[8]) -> uint256[8]: + t: uint256[8] = self._modularAdd(_a, _a, _m) + return self._modularAdd(t, t, _m) From e77e027a4708405bf3b33667a6193cb48da4bd8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E6=9D=91=E9=BE=8D=E7=9F=A2?= Date: Tue, 22 Jan 2019 11:51:36 +0900 Subject: [PATCH 2/6] Remove _compare and bytes conversions (size: 22857) --- contracts/bigint/BigInt.vy | 154 ++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 78 deletions(-) diff --git a/contracts/bigint/BigInt.vy b/contracts/bigint/BigInt.vy index 5add6ef..eac22ee 100644 --- a/contracts/bigint/BigInt.vy +++ b/contracts/bigint/BigInt.vy @@ -4,77 +4,47 @@ # https://github.com/matterinc/RSAAccumulator/blob/master/contracts/RSAAccumulator.sol ### CONSTANTS ### -# FIXME: The sizes of arrays in this file should be replaced with these constants: -# https://github.com/ethereum/vyper/issues/1167 - -N_LIMBS_LENGTH: constant(int128) = 8 -G: constant(uint256) = 3 - -M_LIST_LENGTH: constant(int128) = N_LIMBS_LENGTH +M_LIST_LENGTH: constant(int128) = 8 M_BYTE_COUNT: constant(int128) = 32 * M_LIST_LENGTH -M_BYTE_COUNT_BYTES32: constant(bytes32) = convert(M_BYTE_COUNT, bytes32) # For now, the same lengths are used for the simplicity of impelementation. -BASE_BYTE_COUNT_BYTES32: constant(bytes32) = M_BYTE_COUNT_BYTES32 -E_BYTE_COUNT_BYTES32: constant(bytes32) = M_BYTE_COUNT_BYTES32 +BASE_BYTE_COUNT: constant(int128) = M_BYTE_COUNT +E_BYTE_COUNT: constant(int128) = M_BYTE_COUNT +# Lenth in bytes32 representation +M_BYTE_COUNT_BYTES32: constant(bytes32) = convert(M_BYTE_COUNT, bytes32) +BASE_BYTE_COUNT_BYTES32: constant(bytes32) = convert(BASE_BYTE_COUNT, bytes32) +E_BYTE_COUNT_BYTES32: constant(bytes32) = convert(BASE_BYTE_COUNT, bytes32) PRECOMPILED_BIGMODEXP: constant(address) = 0x0000000000000000000000000000000000000005 - +BIGMODEXP_RES_SIZE: constant(int128) = 32 * 3 + M_BYTE_COUNT + BASE_BYTE_COUNT + E_BYTE_COUNT ### BIG INTEGER ARITHMETIC FUNCTIONS ### -# this assumes that exponent in never larger than 256 bits @private -def _modularExp(_base: uint256[8], _e: uint256, _m: uint256[8]) -> uint256[8]: - e: uint256[8] - e[M_LIST_LENGTH - 1] = _e - - tmp: bytes32[8] +def _bigModExp(_base: uint256[M_LIST_LENGTH], _e: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + # convert UInt256 list to bytes (inlined for code size reduction) + tmp: bytes32[M_LIST_LENGTH] for i in range(M_LIST_LENGTH): tmp[i] = convert(_base[i], bytes32) - base: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) - - for i in range(M_LIST_LENGTH): - tmp[i] = convert(e[i], bytes32) - exponent: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) - - for i in range(M_LIST_LENGTH): - tmp[i] = convert(_m[i], bytes32) - modulus: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) - # ref. https://eips.ethereum.org/EIPS/eip-198 - # 864 = 32 * 3 + + + - data: bytes[864] = concat(BASE_BYTE_COUNT_BYTES32, E_BYTE_COUNT_BYTES32, M_BYTE_COUNT_BYTES32, - base, exponent, modulus) - # NOTE: raw_call doesn't support static call for now. - res: bytes[256] = raw_call(PRECOMPILED_BIGMODEXP, data, outsize=256, gas=2000) - - out: uint256[8] - for i in range(M_LIST_LENGTH): - out[i] = convert(extract32(res, i * 32, type=bytes32), uint256) - return out - - -@private -def _modularExpVariableLength(_base: uint256[8], _e: uint256[8], _m: uint256[8]) -> uint256[8]: - tmp: bytes32[8] - for i in range(M_LIST_LENGTH): - tmp[i] = convert(_base[i], bytes32) - base: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + base: bytes[M_BYTE_COUNT] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + # convert UInt256 list to bytes (inlined for code size reduction) for i in range(M_LIST_LENGTH): tmp[i] = convert(_e[i], bytes32) - exponent: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + exponent: bytes[M_BYTE_COUNT] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + # convert UInt256 list to bytes (inlined for code size reduction) for i in range(M_LIST_LENGTH): tmp[i] = convert(_m[i], bytes32) - modulus: bytes[256] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + modulus: bytes[M_BYTE_COUNT] = concat(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]) + # ref. https://eips.ethereum.org/EIPS/eip-198 - # 864 = 32 * 3 + + + - data: bytes[864] = concat(BASE_BYTE_COUNT_BYTES32, E_BYTE_COUNT_BYTES32, M_BYTE_COUNT_BYTES32, - base, exponent, modulus) + data: bytes[BIGMODEXP_RES_SIZE] = concat( + BASE_BYTE_COUNT_BYTES32, E_BYTE_COUNT_BYTES32, M_BYTE_COUNT_BYTES32, base, exponent, modulus) # NOTE: raw_call doesn't support static call for now. - res: bytes[256] = raw_call(PRECOMPILED_BIGMODEXP, data, outsize=256, gas=2000) + res: bytes[M_BYTE_COUNT] = raw_call(PRECOMPILED_BIGMODEXP, data, outsize=256, gas=2000) - out: uint256[8] + # convert bytes array to UInt256 list (inlined for code size reduction) + out: uint256[M_LIST_LENGTH] for i in range(M_LIST_LENGTH): out[i] = convert(extract32(res, i * 32, type=bytes32), uint256) return out @@ -82,10 +52,10 @@ def _modularExpVariableLength(_base: uint256[8], _e: uint256[8], _m: uint256[8]) @private @constant -def _wrappingSub(_a: uint256[8], _b: uint256[8]) -> uint256[8]: +def _wrappingSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: borrow: bool = False limb: uint256 = 0 - o: uint256[8] + o: uint256[M_LIST_LENGTH] for i in range(M_LIST_LENGTH): j: int128 = M_LIST_LENGTH - i limb = _a[j] @@ -105,13 +75,14 @@ def _wrappingSub(_a: uint256[8], _b: uint256[8]) -> uint256[8]: o[j] = limb - _b[j] return o + @private @constant -def _wrappingAdd(_a: uint256[8], _b: uint256[8]) -> uint256[8]: +def _wrappingAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: carry: bool = False limb: uint256 = 0 subaddition: uint256 = 0 - o: uint256[8] + o: uint256[M_LIST_LENGTH] for i in range(M_LIST_LENGTH): j: int128 = M_LIST_LENGTH - i limb = _a[j] @@ -132,35 +103,47 @@ def _wrappingAdd(_a: uint256[8], _b: uint256[8]) -> uint256[8]: o[j] = subaddition return o + @private @constant -def _compare(_a: uint256[8], _b: uint256[8]) -> int128: +def _modularSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + o: uint256[M_LIST_LENGTH] + + # Comparison (inlined for code size reduction) + comparison: int128 for i in range(M_LIST_LENGTH): if _a[i] > _b[i]: - return 1 + comparison = 1 elif _a[i] < _b[i]: - return -1 - return 0 + comparison = -1 + else: + comparison = 0 -@private -@constant -def _modularSub(_a: uint256[8], _b: uint256[8], _m: uint256[8]) -> uint256[8]: - o: uint256[8] - comparison: int128 = self._compare(_a, _b) if comparison == 0: return o elif comparison == 1: return self._wrappingSub(_a, _b) else: - tmp: uint256[8] = self._wrappingSub(_b, _a) + tmp: uint256[M_LIST_LENGTH] = self._wrappingSub(_b, _a) return self._wrappingSub(_m, tmp) + @private @constant -def _modularAdd(_a: uint256[8], _b: uint256[8], _m: uint256[8]) -> uint256[8]: - space: uint256[8] = self._wrappingSub(_m, _a) - o: uint256[8] - comparison: int128 = self._compare(_a, _b) +def _modularAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + space: uint256[M_LIST_LENGTH] = self._wrappingSub(_m, _a) + o: uint256[M_LIST_LENGTH] + + # Comparison (inlined for code size reduction) + comparison: int128 + for i in range(M_LIST_LENGTH): + if _a[i] > _b[i]: + comparison = 1 + elif _a[i] < _b[i]: + comparison = -1 + else: + comparison = 0 + if comparison == 0: return o elif comparison == 1: @@ -168,15 +151,30 @@ def _modularAdd(_a: uint256[8], _b: uint256[8], _m: uint256[8]) -> uint256[8]: else: return self._wrappingSub(_b, space) -@private -def _modularMul4(_a: uint256[8], _b: uint256[8], _m: uint256[8]) -> uint256[8]: - aPlusB: uint256[8] = self._modularExp(self._modularAdd(_a, _b, _m), 2, _m) - aMinusB: uint256[8] = self._modularExp(self._modularSub(_a, _b, _m), 2, _m) + +### PUBLIC FUNCTIONS ### +@public +def modularExp(_base: uint256[M_LIST_LENGTH], _e: uint256, _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + e: uint256[M_LIST_LENGTH] + e[M_LIST_LENGTH - 1] = _e + return self._bigModExp(_base, e, _m) + +@public +def modularExpVariableLength(_base: uint256[M_LIST_LENGTH], _e: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + return self._bigModExp(_base, _e, _m) + +# 4ab = (a + b)^2 - (a - b)^2 +@public +def modularMul4(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + two: uint256[M_LIST_LENGTH] + two[M_LIST_LENGTH - 1] = 2 + aPlusB: uint256[M_LIST_LENGTH] = self._bigModExp(self._modularAdd(_a, _b, _m), two, _m) + aMinusB: uint256[M_LIST_LENGTH] = self._bigModExp(self._modularSub(_a, _b, _m), two, _m) return self._modularSub(aPlusB, aMinusB, _m) -# cheat and just do two additions -@private +# 4a = (a + a) + (a + a) +@public @constant -def _modularMulBy4(_a: uint256[8], _m: uint256[8]) -> uint256[8]: - t: uint256[8] = self._modularAdd(_a, _a, _m) +def modularMulBy4(_a: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + t: uint256[M_LIST_LENGTH] = self._modularAdd(_a, _a, _m) return self._modularAdd(t, t, _m) From edbdea7db1d4bc74673f078445770f316c26d39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E6=9D=91=E9=BE=8D=E7=9F=A2?= Date: Tue, 22 Jan 2019 12:20:28 +0900 Subject: [PATCH 3/6] Add public modularAdd and modularSub (size: 24391) --- contracts/bigint/BigInt.vy | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/contracts/bigint/BigInt.vy b/contracts/bigint/BigInt.vy index eac22ee..d7c57bf 100644 --- a/contracts/bigint/BigInt.vy +++ b/contracts/bigint/BigInt.vy @@ -153,16 +153,30 @@ def _modularAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint ### PUBLIC FUNCTIONS ### +@public +@constant +def modularAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + return self._modularAdd(_a, _b, _m) + + +@public +@constant +def modularSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + return self._modularSub(_a, _b, _m) + + @public def modularExp(_base: uint256[M_LIST_LENGTH], _e: uint256, _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: e: uint256[M_LIST_LENGTH] e[M_LIST_LENGTH - 1] = _e return self._bigModExp(_base, e, _m) + @public def modularExpVariableLength(_base: uint256[M_LIST_LENGTH], _e: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: return self._bigModExp(_base, _e, _m) + # 4ab = (a + b)^2 - (a - b)^2 @public def modularMul4(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: @@ -172,6 +186,7 @@ def modularMul4(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint aMinusB: uint256[M_LIST_LENGTH] = self._bigModExp(self._modularSub(_a, _b, _m), two, _m) return self._modularSub(aPlusB, aMinusB, _m) + # 4a = (a + a) + (a + a) @public @constant From c3aeb74d2e40f44ddcb1e7066049b83cb5ad619d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E6=9D=91=E9=BE=8D=E7=9F=A2?= Date: Tue, 22 Jan 2019 21:40:52 +0900 Subject: [PATCH 4/6] Fix arithmetic and comment out modularAdd & modularSub (size: 24013) --- contracts/bigint/BigInt.vy | 102 +++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 43 deletions(-) diff --git a/contracts/bigint/BigInt.vy b/contracts/bigint/BigInt.vy index d7c57bf..7960b7e 100644 --- a/contracts/bigint/BigInt.vy +++ b/contracts/bigint/BigInt.vy @@ -53,25 +53,29 @@ def _bigModExp(_base: uint256[M_LIST_LENGTH], _e: uint256[M_LIST_LENGTH], _m: ui @private @constant def _wrappingSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + """ + Assumes _a > _b, otherwise returns _a - _b + 2 ** (256 * M_LIST_LENGTH)(finishes with borrow = True) + Assumes _a - _b < _m, otherwise the output is larger or equal to _m + """ borrow: bool = False limb: uint256 = 0 o: uint256[M_LIST_LENGTH] for i in range(M_LIST_LENGTH): - j: int128 = M_LIST_LENGTH - i + j: int128 = M_LIST_LENGTH - 1 - i limb = _a[j] if borrow: if limb == 0: borrow = True - limb -= 1 - o[j] = limb - _b[j] + o[j] = MAX_UINT256 - _b[j] + continue else: limb -= 1 - if limb >= _b[j]: - borrow = False - o[j] = limb - _b[j] - else: - if limb < _b[j]: - borrow = True + if limb < _b[j]: + borrow = True + # 2 ** 256 - diff + o[j] = MAX_UINT256 - (_b[j] - limb) + 1 + else: + borrow = False o[j] = limb - _b[j] return o @@ -79,36 +83,39 @@ def _wrappingSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH]) -> uint @private @constant def _wrappingAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + """ + Assumes _a + _b < _m, otherwise the output is larger or equal to _m + """ carry: bool = False limb: uint256 = 0 subaddition: uint256 = 0 o: uint256[M_LIST_LENGTH] for i in range(M_LIST_LENGTH): - j: int128 = M_LIST_LENGTH - i + j: int128 = M_LIST_LENGTH - 1 - i limb = _a[j] if carry: - if limb == 0: + if limb == MAX_UINT256: # NOTE: The original seems wrong here. carry = True o[j] = _b[j] + continue else: limb += 1 - subaddition = limb + _b[j] - if subaddition >= limb: - carry = False - o[j] = subaddition + if limb > MAX_UINT256 - _b[j]: + carry = True + o[j] = limb - (MAX_UINT256 - _b[j] + 1) else: - subaddition = limb + _b[j] - if subaddition < limb: - carry = True - o[j] = subaddition + carry = False + o[j] = limb + _b[j] return o @private @constant def _modularSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: - o: uint256[M_LIST_LENGTH] - + """ + Assumes _a - _b < _m, otherwise the output is larger or equal to _m + Assumes _b - _a < _m, otherwise returns _m - (_b - _a) + 2 ** (256 * M_LIST_LENGTH) when _a < _b + """ # Comparison (inlined for code size reduction) comparison: int128 for i in range(M_LIST_LENGTH): @@ -119,11 +126,12 @@ def _modularSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint else: comparison = 0 - if comparison == 0: + if comparison == 0: # _a = _b + o: uint256[M_LIST_LENGTH] return o - elif comparison == 1: + elif comparison == 1: # _a > _b return self._wrappingSub(_a, _b) - else: + else: # _a < _b tmp: uint256[M_LIST_LENGTH] = self._wrappingSub(_b, _a) return self._wrappingSub(_m, tmp) @@ -131,39 +139,33 @@ def _modularSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint @private @constant def _modularAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + """ + Assumes _a <= _m, otherwise space = _m - _a + 2 ** (256 * M_LIST_LENGTH) + Assumes _a + _b <= 2 * _m? (otherwise _b - space >= _m) when space < _b + """ + # See how much "space" has left before an overflow space: uint256[M_LIST_LENGTH] = self._wrappingSub(_m, _a) - o: uint256[M_LIST_LENGTH] - + # Comparison (inlined for code size reduction) comparison: int128 for i in range(M_LIST_LENGTH): - if _a[i] > _b[i]: + if space[i] > _b[i]: comparison = 1 - elif _a[i] < _b[i]: + elif space[i] < _b[i]: comparison = -1 else: comparison = 0 - if comparison == 0: + if comparison == 0: # space = _b + o: uint256[M_LIST_LENGTH] return o - elif comparison == 1: + elif comparison == 1: # space > _b return self._wrappingAdd(_a, _b) - else: + else: # space < _b return self._wrappingSub(_b, space) ### PUBLIC FUNCTIONS ### -@public -@constant -def modularAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: - return self._modularAdd(_a, _b, _m) - - -@public -@constant -def modularSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: - return self._modularSub(_a, _b, _m) - @public def modularExp(_base: uint256[M_LIST_LENGTH], _e: uint256, _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: @@ -177,7 +179,7 @@ def modularExpVariableLength(_base: uint256[M_LIST_LENGTH], _e: uint256[M_LIST_L return self._bigModExp(_base, _e, _m) -# 4ab = (a + b)^2 - (a - b)^2 +# 4ab = (a + b)**2 - (a - b)**2 @public def modularMul4(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: two: uint256[M_LIST_LENGTH] @@ -193,3 +195,17 @@ def modularMul4(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint def modularMulBy4(_a: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: t: uint256[M_LIST_LENGTH] = self._modularAdd(_a, _a, _m) return self._modularAdd(t, t, _m) + + +# NOTE: modularAdd and modularSub are commented out here due to the code size issue (EIP170). +# When you use them, remove other public functions instead to reduce the code size. +# @public +# @constant +# def modularAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: +# return self._modularAdd(_a, _b, _m) + + +# @public +# @constant +# def modularSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: +# return self._modularSub(_a, _b, _m) From cd10c3d92f28412f089a49584e4bc52d3f3757ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E6=9D=91=E9=BE=8D=E7=9F=A2?= Date: Tue, 22 Jan 2019 21:52:57 +0900 Subject: [PATCH 5/6] Add bigint test file --- .circleci/config.yml | 15 ++++++++ tests/bigint/__init__.py | 0 tests/bigint/test_bigint.py | 76 +++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 tests/bigint/__init__.py create mode 100644 tests/bigint/test_bigint.py diff --git a/.circleci/config.yml b/.circleci/config.yml index 6de0ba2..8f2cca3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,6 +63,14 @@ jobs: path: ~/verified-vyper-contracts - run: ./test.sh ecdsa + biginttest: + working_directory: ~/verified-vyper-contracts/tests + docker: + - image: python:3.6.7 + steps: + - checkout: + path: ~/verified-vyper-contracts + - run: ./test.sh bigint workflows: version: 2 @@ -117,3 +125,10 @@ workflows: - /ecdsa\/.*/ - /all\/.*/ - master + - biginttest: + filters: + branches: + only: + - /bigint\/.*/ + - /all\/.*/ + - master diff --git a/tests/bigint/__init__.py b/tests/bigint/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/bigint/test_bigint.py b/tests/bigint/test_bigint.py new file mode 100644 index 0000000..6eef529 --- /dev/null +++ b/tests/bigint/test_bigint.py @@ -0,0 +1,76 @@ +import pytest + +from web3.exceptions import ( + ValidationError +) + +# RSA-2048 (https://en.wikipedia.org/wiki/RSA_numbers#RSA-2048) +M = 25195908475657893494027183240048398571429282126204032027777137836043662020707595556264018525880784406918290641249515082189298559149176184502808489120072844992687392807287776735971418347270261896375014971824691165077613379859095700097330459748808428401797429100642458691817195118746121515172654632282216869987549182422433637259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133844143603833904414952634432190114657544454178424020924616515723350778707749817125772467962926386356373289912154831438167899885040445364023527381951378636564391212010397122822120720357 +M_LIST_LENGTH = 8 + + +def int_to_list(inp): + """ + e.g. int_to_list(2**256) = [0, 0, 0, 0, 0, 0, 1, 0] + """ + hex_str = format(inp, '0512x') + return [int(hex_str[64 * i: 64 * (i + 1)], 16) for i in range(M_LIST_LENGTH)] + + +def list_to_int(inp): + out = 0 + for i in range(M_LIST_LENGTH): + out += 2 ** (256 * i) * inp[M_LIST_LENGTH -1 - i] + return out + + +M_LIST = int_to_list(M) + + +@pytest.fixture +def c(get_contract, w3): + with open('../contracts/bigint/BigInt.vy') as f: + code = f.read() + c = get_contract(code) + return c + +@pytest.fixture +def c2(get_contract, w3): + """ + BigInt.vy with modularAdd and modularSub + """ + with open('../contracts/bigint/BigInt.vy') as f: + code = f.read() + + EXP_CODE = """@public +def modularExp(_base: uint256[M_LIST_LENGTH], _e: uint256, _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + e: uint256[M_LIST_LENGTH] + e[M_LIST_LENGTH - 1] = _e + return self._bigModExp(_base, e, _m) + + +@public +def modularExpVariableLength(_base: uint256[M_LIST_LENGTH], _e: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + return self._bigModExp(_base, _e, _m)""" + + ADD_AND_SUB_CODE = """@public +@constant +def modularAdd(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + return self._modularAdd(_a, _b, _m) + + +@public +@constant +def modularSub(_a: uint256[M_LIST_LENGTH], _b: uint256[M_LIST_LENGTH], _m: uint256[M_LIST_LENGTH]) -> uint256[M_LIST_LENGTH]: + return self._modularSub(_a, _b, _m)""" + code = code.replace(EXP_CODE, ADD_AND_SUB_CODE) + c = get_contract(code) + return c + + +# def test_modularSub(c2): +# assert list_to_int(c2.modularSub(int_to_list(1), int_to_list(1), M_LIST)) == 0 + + +# def test_modularAdd(c2): +# assert list_to_int(c2.modularAdd(int_to_list(1), int_to_list(1), M_LIST)) == 1 + 1 From 5443d3990271b1983194595ee530cd3147554591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E6=9D=91=E9=BE=8D=E7=9F=A2?= Date: Tue, 22 Jan 2019 22:00:10 +0900 Subject: [PATCH 6/6] Fix flake8 errors --- tests/bigint/test_bigint.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/bigint/test_bigint.py b/tests/bigint/test_bigint.py index 6eef529..1586bd0 100644 --- a/tests/bigint/test_bigint.py +++ b/tests/bigint/test_bigint.py @@ -1,9 +1,5 @@ import pytest -from web3.exceptions import ( - ValidationError -) - # RSA-2048 (https://en.wikipedia.org/wiki/RSA_numbers#RSA-2048) M = 25195908475657893494027183240048398571429282126204032027777137836043662020707595556264018525880784406918290641249515082189298559149176184502808489120072844992687392807287776735971418347270261896375014971824691165077613379859095700097330459748808428401797429100642458691817195118746121515172654632282216869987549182422433637259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133844143603833904414952634432190114657544454178424020924616515723350778707749817125772467962926386356373289912154831438167899885040445364023527381951378636564391212010397122822120720357 M_LIST_LENGTH = 8 @@ -20,10 +16,10 @@ def int_to_list(inp): def list_to_int(inp): out = 0 for i in range(M_LIST_LENGTH): - out += 2 ** (256 * i) * inp[M_LIST_LENGTH -1 - i] + out += 2 ** (256 * i) * inp[M_LIST_LENGTH - 1 - i] return out - + M_LIST = int_to_list(M) @@ -34,6 +30,7 @@ def c(get_contract, w3): c = get_contract(code) return c + @pytest.fixture def c2(get_contract, w3): """