diff --git a/contracts/certificate/signers/CECDSASHA2Signer.sol b/contracts/certificate/signers/CECDSASHA2Signer.sol index fefbae1..48475a8 100644 --- a/contracts/certificate/signers/CECDSASHA2Signer.sol +++ b/contracts/certificate/signers/CECDSASHA2Signer.sol @@ -32,6 +32,13 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { uint256 y; } + struct GH { + uint256 gx; + uint256 gy; + uint256 hx; + uint256 hy; + } + function __CECDSASHA2Signer_init() external initializer {} function verifyICAOSignature( @@ -45,6 +52,9 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { (inputs.r, inputs.s) = U384.init2(icaoMemberSignature_); (inputs.x, inputs.y) = U384.init2(icaoMemberKey_); + uint256 p = hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" + .init(); + // secp384r1 parameters Parameters memory params = Parameters({ a: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC" @@ -55,13 +65,12 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { .init(), gy: hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f" .init(), - p: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF" - .init(), + p: p, n: hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973" .init(), lowSmax: hex"7fffffffffffffffffffffffffffffffffffffffffffffffe3b1a6c0fa1b96efac0d06d9245853bd76760cb5666294b9" .init(), - call: U384.initCall(), + call: U384.initCall(p), three: U384.init(3) }); @@ -80,34 +89,17 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { } uint256 message = uint256(sha256(x509SignedAttributes_)).init(); + uint256 scalar1 = U384.moddiv(params.call, message, inputs.s, params.n); + uint256 scalar2 = U384.moddiv(params.call, inputs.r, inputs.s, params.n); - (uint256 x1, uint256 y1) = _multiplyScalar( + (uint256 x, , uint256 z) = _doubleScalarMultiplication( 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) - ); - - (x1, y1, x2) = _addProj( - params.call, - params.p, - params.three, - params.a, - x1, - y1, - U384.init(1), - x2, - y2, - U384.init(1) + GH(params.gx, params.gy, inputs.x, inputs.y), + scalar1, + scalar2 ); - return U384.eq(U384.moddiv(params.call, x1, x2, params.p), inputs.r); + return U384.eq(U384.moddiv(params.call, x, z, params.p), inputs.r); } } @@ -127,15 +119,15 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { 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); + uint256 RHS = U384.modexp(call, x, 3); if (!U384.eqInteger(a, 0)) { - RHS = U384.modadd(call, RHS, U384.modmul(call, x, a, p), p); // x^3 + a*x + RHS = U384.modadd(RHS, U384.modmul(call, x, a), p); // x^3 + a*x } if (!U384.eqInteger(b, 0)) { - RHS = U384.modadd(call, RHS, b, p); // x^3 + a*x + b + RHS = U384.modadd(RHS, b, p); // x^3 + a*x + b } return U384.eq(LHS, RHS); @@ -143,101 +135,88 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { } /** - * @dev Multiply an elliptic curve point by a scalar. + * @dev Compute the double scalar multiplication scalar1*G + scalar2*H. */ - function _multiplyScalar( + function _doubleScalarMultiplication( Parameters memory params, - uint256 x0, - uint256 y0, - uint256 scalar - ) internal view returns (uint256 x1, uint256 y1) { + GH memory gh, + uint256 scalar1, + uint256 scalar2 + ) internal view returns (uint256 x, uint256 y, uint256 z) { unchecked { - if (U384.eqInteger(scalar, 0)) { - return (U384.init(0), U384.init(0)); // zero affine coordinates - } 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); + /// We use 4-bit masks where the first 2 bits refer to `scalar1` and the last 2 bits refer to `scalar2`. + uint256[3][16] memory points = _precomputePointsTable( + params.call, + params.p, + params.three, + params.a, + gh + ); - uint256 highBits_; - uint256 lowBits_; + uint256 scalar1Bits_; + uint256 scalar2Bits_; assembly { - highBits_ := mload(scalar) - lowBits_ := mload(add(scalar, 0x20)) + scalar1Bits_ := mload(scalar1) + scalar2Bits_ := mload(scalar2) } - if (lowBits_ & 1 == 0) { - x1 = U384.init(0); - y1 = U384.init(0); - } else { - x1 = U384.copy(x0); - y1 = U384.copy(y0); - } + x = U384.init(0); + y = U384.init(0); + z = U384.init(1); + + for (uint256 word = 2; word <= 184; word += 2) { + (x, y, z) = _twiceProj(params.call, params.p, params.three, params.a, x, y, z); + (x, y, z) = _twiceProj(params.call, params.p, params.three, params.a, x, y, z); + + uint256 mask = (((scalar1Bits_ >> (184 - word)) & 0x03) << 2) | + ((scalar2Bits_ >> (184 - word)) & 0x03); - lowBits_ = (lowBits_ >> 1) | (highBits_ << 255); - highBits_ >>= 1; - - while (lowBits_ > 0 || highBits_ > 0) { - (base2X, base2Y, base2Z) = _twiceProj( - params.call, - params.p, - params.three, - params.a, - base2X, - base2Y, - base2Z - ); - - if (lowBits_ & 1 == 1) { - (x1, y1, z1) = _addProj( + if (mask != 0) { + (x, y, z) = _addProj( params.call, params.p, params.three, params.a, - base2X, - base2Y, - base2Z, - x1, - y1, - z1 + points[mask][0], + points[mask][1], + points[mask][2], + x, + y, + z ); } + } - lowBits_ = (lowBits_ >> 1) | (highBits_ << 255); - highBits_ >>= 1; + assembly { + scalar1Bits_ := mload(add(scalar1, 0x20)) + scalar2Bits_ := mload(add(scalar2, 0x20)) } - uint256 p_ = params.p; - uint256 call_ = params.call; + for (uint256 word = 2; word <= 256; word += 2) { + (x, y, z) = _twiceProj(params.call, params.p, params.three, params.a, x, y, z); + (x, y, z) = _twiceProj(params.call, params.p, params.three, params.a, x, y, z); - return (U384.moddiv(call_, x1, z1, p_), U384.moddiv(call_, y1, z1, p_)); - } - } - - /** - * @dev Double an elliptic curve point in affine coordinates. - */ - function _twice( - uint256 call, - uint256 p, - uint256 three, - uint256 a, - uint256 x0, - uint256 y0 - ) internal view returns (uint256, uint256) { - unchecked { - uint256 z0; + uint256 mask = (((scalar1Bits_ >> (256 - word)) & 0x03) << 2) | + ((scalar2Bits_ >> (256 - word)) & 0x03); - (x0, y0, z0) = _twiceProj(call, p, three, a, x0, y0, U384.init(1)); + if (mask != 0) { + (x, y, z) = _addProj( + params.call, + params.p, + params.three, + params.a, + points[mask][0], + points[mask][1], + points[mask][2], + x, + y, + z + ); + } + } - return (U384.moddiv(call, x0, z0, p), U384.moddiv(call, y0, z0, p)); + return (x, y, z); } } @@ -256,45 +235,45 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { ) internal view returns (uint256 x1, uint256 y1, uint256 z1) { unchecked { if (U384.eqInteger(x0, 0) && U384.eqInteger(y0, 0)) { - return (U384.init(0), U384.init(1), U384.init(0)); // zero proj + return (U384.init(0), U384.init(0), U384.init(1)); // zero proj } - uint256 u = U384.modmul(call, y0, z0, p); - U384.modshl1Assign(call, u, p); + uint256 u = U384.modmul(call, y0, z0); + U384.modshl1Assign(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); + U384.modmulAssign(call, x1, y0); + U384.modshl1Assign(x1, p); - x0 = U384.modexp(call, x0, 2, p); + x0 = U384.modexp(call, x0, 2); - y1 = U384.modmul(call, x0, three, p); + y1 = U384.modmul(call, x0, three); - z0 = U384.modexp(call, z0, 2, p); - U384.modmulAssign(call, z0, a, p); - U384.modaddAssign(call, y1, z0, p); + z0 = U384.modexp(call, z0, 2); + U384.modmulAssign(call, z0, a); + U384.modaddAssign(y1, z0, p); - z1 = U384.modexp(call, y1, 2, p); - U384.modshl1AssignTo(call, x0, x1, p); + z1 = U384.modexp(call, y1, 2); + U384.modshl1AssignTo(x0, x1, p); uint256 diff = U384.sub(p, x0); - U384.modaddAssign(call, z1, diff, p); + U384.modaddAssign(z1, diff, p); U384.subAssignTo(diff, p, z1); - U384.modaddAssignTo(call, x0, x1, diff, p); - U384.modmulAssign(call, x0, y1, p); + U384.modaddAssignTo(x0, x1, diff, p); + U384.modmulAssign(call, x0, y1); - y0 = U384.modmul(call, y0, u, p); - U384.modexpAssign(call, y0, 2, p); - U384.modshl1Assign(call, y0, p); + y0 = U384.modmul(call, y0, u); + U384.modexpAssign(call, y0, 2); + U384.modshl1Assign(y0, p); U384.subAssignTo(diff, p, y0); - U384.modaddAssignTo(call, y1, x0, diff, p); + U384.modaddAssignTo(y1, x0, diff, p); - U384.modmulAssignTo(call, x1, u, z1, p); + U384.modmulAssignTo(call, x1, u, z1); - U384.modexpAssignTo(call, z1, u, 2, p); - U384.modmulAssign(call, z1, u, p); + U384.modexpAssignTo(call, z1, u, 2); + U384.modmulAssign(call, z1, u); } } @@ -316,25 +295,25 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { unchecked { if (U384.eqInteger(x0, 0) && U384.eqInteger(y0, 0)) { - return (x1, y1, z1); + return (x1.copy(), y1.copy(), z1.copy()); } else if (U384.eqInteger(x1, 0) && U384.eqInteger(y1, 0)) { - return (x0, y0, z0); + return (x0.copy(), y0.copy(), z0.copy()); } - 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); + x2 = U384.modmul(call, y0, z1); + y2 = U384.modmul(call, y1, z0); + z2 = U384.modmul(call, x0, z1); + y1 = U384.modmul(call, x1, z0); if (U384.eq(z2, y1)) { if (U384.eq(x2, y2)) { return _twiceProj(call, p, three, a, x0, y0, z0); } else { - return (U384.init(0), U384.init(1), U384.init(0)); // zero proj + return (U384.init(0), U384.init(0), U384.init(1)); // zero proj } } - a = U384.modmul(call, z0, z1, p); + a = U384.modmul(call, z0, z1); return _addProj2(call, a, z2, p, y1, y2, x2); } @@ -354,35 +333,221 @@ contract CECDSASHA2Signer is ICertificateSigner, Initializable { ) internal view returns (uint256 x2, uint256 y2, uint256 z2) { unchecked { uint256 diff = U384.sub(p, t1); - y2 = U384.modadd(call, t0, diff, p); + y2 = U384.modadd(t0, diff, p); U384.subAssignTo(diff, p, u1); - x2 = U384.modadd(call, u0, diff, p); - uint256 u2 = U384.modexp(call, x2, 2, p); + x2 = U384.modadd(u0, diff, p); + uint256 u2 = U384.modexp(call, x2, 2); - z2 = U384.modexp(call, y2, 2, p); + z2 = U384.modexp(call, y2, 2); - U384.modmulAssign(call, z2, v, p); - u1 = U384.modadd(call, u1, u0, p); - U384.modmulAssign(call, u1, u2, p); + U384.modmulAssign(call, z2, v); + u1 = U384.modadd(u1, u0, p); + U384.modmulAssign(call, u1, u2); U384.subAssignTo(diff, p, u1); - U384.modaddAssign(call, z2, diff, p); + U384.modaddAssign(z2, diff, p); - uint256 u3 = U384.modmul(call, u2, x2, p); + uint256 u3 = U384.modmul(call, u2, x2); - U384.modmulAssign(call, x2, z2, p); + U384.modmulAssign(call, x2, z2); - u0 = U384.modmul(call, u0, u2, p); + u0 = U384.modmul(call, u0, u2); U384.subAssignTo(diff, p, z2); - U384.modaddAssign(call, u0, diff, p); - U384.modmulAssign(call, y2, u0, p); - t0 = U384.modmul(call, t0, u3, p); + U384.modaddAssign(u0, diff, p); + U384.modmulAssign(call, y2, u0); + t0 = U384.modmul(call, t0, u3); U384.subAssignTo(diff, p, t0); - U384.modaddAssign(call, y2, diff, p); + U384.modaddAssign(y2, diff, p); - U384.modmulAssignTo(call, z2, u3, v, p); + U384.modmulAssignTo(call, z2, u3, v); } } + + function _precomputePointsTable( + uint256 call, + uint256 p, + uint256 three, + uint256 a, + GH memory gh + ) private view returns (uint256[3][16] memory points) { + /// 0b0100: 1G + 0H + (points[0x04][0], points[0x04][1], points[0x04][2]) = ( + gh.gx.copy(), + gh.gy.copy(), + U384.init(1) + ); + /// 0b1000: 2G + 0H + (points[0x08][0], points[0x08][1], points[0x08][2]) = _twiceProj( + call, + p, + three, + a, + points[0x04][0], + points[0x04][1], + points[0x04][2] + ); + /// 0b1100: 3G + 0H + (points[0x0C][0], points[0x0C][1], points[0x0C][2]) = _addProj( + call, + p, + three, + a, + points[0x04][0], + points[0x04][1], + points[0x04][2], + points[0x08][0], + points[0x08][1], + points[0x08][2] + ); + /// 0b0001: 0G + 1H + (points[0x01][0], points[0x01][1], points[0x01][2]) = ( + gh.hx.copy(), + gh.hy.copy(), + U384.init(1) + ); + /// 0b0010: 0G + 2H + (points[0x02][0], points[0x02][1], points[0x02][2]) = _twiceProj( + call, + p, + three, + a, + points[0x01][0], + points[0x01][1], + points[0x01][2] + ); + /// 0b0011: 0G + 3H + (points[0x03][0], points[0x03][1], points[0x03][2]) = _addProj( + call, + p, + three, + a, + points[0x01][0], + points[0x01][1], + points[0x01][2], + points[0x02][0], + points[0x02][1], + points[0x02][2] + ); + /// 0b0101: 1G + 1H + (points[0x05][0], points[0x05][1], points[0x05][2]) = _addProj( + call, + p, + three, + a, + points[0x04][0], + points[0x04][1], + points[0x04][2], + points[0x01][0], + points[0x01][1], + points[0x01][2] + ); + /// 0b0110: 1G + 2H + (points[0x06][0], points[0x06][1], points[0x06][2]) = _addProj( + call, + p, + three, + a, + points[0x04][0], + points[0x04][1], + points[0x04][2], + points[0x02][0], + points[0x02][1], + points[0x02][2] + ); + /// 0b0111: 1G + 3H + (points[0x07][0], points[0x07][1], points[0x07][2]) = _addProj( + call, + p, + three, + a, + points[0x04][0], + points[0x04][1], + points[0x04][2], + points[0x03][0], + points[0x03][1], + points[0x03][2] + ); + /// 0b1001: 2G + 1H + (points[0x09][0], points[0x09][1], points[0x09][2]) = _addProj( + call, + p, + three, + a, + points[0x08][0], + points[0x08][1], + points[0x08][2], + points[0x01][0], + points[0x01][1], + points[0x01][2] + ); + /// 0b1010: 2G + 2H + (points[0x0A][0], points[0x0A][1], points[0x0A][2]) = _addProj( + call, + p, + three, + a, + points[0x08][0], + points[0x08][1], + points[0x08][2], + points[0x02][0], + points[0x02][1], + points[0x02][2] + ); + /// 0b1011: 2G + 3H + (points[0x0B][0], points[0x0B][1], points[0x0B][2]) = _addProj( + call, + p, + three, + a, + points[0x08][0], + points[0x08][1], + points[0x08][2], + points[0x03][0], + points[0x03][1], + points[0x03][2] + ); + /// 0b1101: 3G + 1H + (points[0x0D][0], points[0x0D][1], points[0x0D][2]) = _addProj( + call, + p, + three, + a, + points[0x0C][0], + points[0x0C][1], + points[0x0C][2], + points[0x01][0], + points[0x01][1], + points[0x01][2] + ); + /// 0b1110: 3G + 2H + (points[0x0E][0], points[0x0E][1], points[0x0E][2]) = _addProj( + call, + p, + three, + a, + points[0x0C][0], + points[0x0C][1], + points[0x0C][2], + points[0x02][0], + points[0x02][1], + points[0x02][2] + ); + /// 0b1111: 3G + 3H + (points[0x0F][0], points[0x0F][1], points[0x0F][2]) = _addProj( + call, + p, + three, + a, + points[0x0C][0], + points[0x0C][1], + points[0x0C][2], + points[0x03][0], + points[0x03][1], + points[0x03][2] + ); + + return points; + } } diff --git a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol index 24e3ed3..848a201 100644 --- a/contracts/passport/authenticators/PECDSASHA1Authenticator.sol +++ b/contracts/passport/authenticators/PECDSASHA1Authenticator.sol @@ -384,7 +384,7 @@ contract PECDSASHA1Authenticator { * @dev Return the zero curve in projective coordinates. */ function _zeroProj() internal pure returns (uint256 x, uint256 y, uint256 z) { - return (0, 1, 0); + return (0, 0, 1); } /** diff --git a/contracts/utils/U384.sol b/contracts/utils/U384.sol index d4f0716..051ac08 100644 --- a/contracts/utils/U384.sol +++ b/contracts/utils/U384.sol @@ -4,7 +4,11 @@ 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; + + uint256 private constant CALL_ALLOCATION = 3 * 288; + + uint256 private constant MUL_OFFSET = 288; + uint256 private constant EXP_OFFSET = 2 * 288; function init(uint256 from_) internal pure returns (uint256 handler_) { unchecked { @@ -58,23 +62,28 @@ library U384 { } } - function assign(uint256 to_, uint256 from_) internal pure { - assembly { - mstore(to_, mload(from_)) - mstore(add(to_, 0x20), mload(add(from_, 0x20))) - } - } + function initCall(uint256 m_) internal pure returns (uint256 handler_) { + unchecked { + handler_ = _allocate(CALL_ALLOCATION); - function assignInteger(uint256 to_, uint256 fromInteger_) internal pure { - assembly { - mstore(to_, 0x00) - mstore(add(to_, 0x20), fromInteger_) - } - } + assembly { + let call_ := add(handler_, MUL_OFFSET) - function initCall() internal pure returns (uint256 handler_) { - unchecked { - return _allocate(CALL_ALLOCATION); + 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))) + + call_ := add(handler_, EXP_OFFSET) + + mstore(call_, 0x40) + mstore(add(0x20, call_), 0x20) + mstore(add(0x40, call_), 0x40) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) + } } } @@ -136,50 +145,20 @@ library U384 { } } - function cmpInteger(uint256 a_, uint256 bInteger_) internal pure returns (int256 cmp_) { - unchecked { - 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; - } - } - } - function modexp( uint256 call_, uint256 b_, - uint256 eInteger_, - uint256 m_ + uint256 eInteger_ ) internal view returns (uint256 r_) { unchecked { r_ = _allocate(SHORT_ALLOCATION); assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) + call_ := add(call_, EXP_OFFSET) + 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)) } @@ -188,16 +167,13 @@ library U384 { } } - function modexpAssign(uint256 call_, uint256 b_, uint256 eInteger_, uint256 m_) internal view { + function modexpAssign(uint256 call_, uint256 b_, uint256 eInteger_) internal view { assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) + call_ := add(call_, EXP_OFFSET) + 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)) } @@ -207,175 +183,153 @@ library U384 { uint256 call_, uint256 to_, uint256 b_, - uint256 eInteger_, - uint256 m_ + uint256 eInteger_ ) internal view { assembly { - mstore(call_, 0x40) - mstore(add(0x20, call_), 0x20) - mstore(add(0x40, call_), 0x40) + call_ := add(call_, EXP_OFFSET) + 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_) { + function modadd(uint256 a_, uint256 b_, uint256 m_) internal view returns (uint256 r_) { unchecked { r_ = _allocate(SHORT_ALLOCATION); - _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))) + _add(a_, b_, r_); - pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) + if (cmp(r_, m_) >= 0) { + _subFrom(r_, m_); } return r_; } } - function modaddAssign(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view { + function modaddAssign(uint256 a_, uint256 b_, uint256 m_) internal view { unchecked { - _add(a_, b_, call_ + 0x60); + _addTo(a_, b_); - 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))) + if (cmp(a_, m_) >= 0) { + return _subFrom(a_, m_); + } + } + } + + function modaddAssignTo(uint256 to_, uint256 a_, uint256 b_, uint256 m_) internal view { + unchecked { + _add(a_, b_, to_); - pop(staticcall(gas(), 0x5, call_, 0x0100, a_, 0x40)) + if (cmp(to_, m_) >= 0) { + return _subFrom(to_, m_); } } } - function modaddAssignTo( - uint256 call_, - uint256 to_, - uint256 a_, - uint256 b_, - uint256 m_ - ) internal view { + function modmul(uint256 call_, uint256 a_, uint256 b_) internal view returns (uint256 r_) { unchecked { - _add(a_, b_, call_ + 0x60); + r_ = _allocate(SHORT_ALLOCATION); + + _mul(a_, b_, call_ + MUL_OFFSET + 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))) + call_ := add(call_, MUL_OFFSET) - pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) } + + return r_; } } - function mod(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { + function modmulAssign(uint256 call_, uint256 a_, uint256 b_) internal view { unchecked { - r_ = modexp(call_, a_, 1, m_); + _mul(a_, b_, call_ + MUL_OFFSET + 0x60); - return r_; + assembly { + call_ := add(call_, MUL_OFFSET) + + pop(staticcall(gas(), 0x5, call_, 0x0120, a_, 0x40)) + } } } - function modsub( - uint256 call_, - uint256 a_, - uint256 b_, - uint256 m_ - ) internal view returns (uint256 r_) { + function modmulAssignTo(uint256 call_, uint256 to_, uint256 a_, uint256 b_) internal view { unchecked { - r_ = _allocate(SHORT_ALLOCATION); - - _sub(a_, b_, call_ + 0x60); + _mul(a_, b_, call_ + MUL_OFFSET + 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))) + call_ := add(call_, MUL_OFFSET) - pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0120, to_, 0x40)) } + } + } + + function sub(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { + unchecked { + r_ = _allocate(SHORT_ALLOCATION); + + _sub(a_, b_, r_); return r_; } } - function modmul( - uint256 call_, - uint256 a_, - uint256 b_, - uint256 m_ - ) internal view returns (uint256 r_) { + function subAssignTo(uint256 to_, uint256 a_, uint256 b_) internal pure { unchecked { - r_ = _allocate(SHORT_ALLOCATION); + _sub(a_, b_, to_); + } + } - _mul(a_, b_, call_ + 0x60); + function modshl1(uint256 a_, uint256 m_) internal view returns (uint256 r_) { + unchecked { + r_ = _allocate(SHORT_ALLOCATION); - 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))) + _shl1(a_, r_); - pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) + if (cmp(r_, m_) >= 0) { + _subFrom(r_, m_); } return r_; } } - function modmulAssign(uint256 call_, uint256 a_, uint256 b_, uint256 m_) internal view { + function modshl1Assign(uint256 a_, uint256 m_) internal view { unchecked { - _mul(a_, b_, call_ + 0x60); + _shl1To(a_); - 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))) + if (cmp(a_, m_) >= 0) { + _subFrom(a_, m_); + } + } + } - pop(staticcall(gas(), 0x5, call_, 0x0120, a_, 0x40)) + function modshl1AssignTo(uint256 to_, uint256 a_, uint256 m_) internal view { + unchecked { + _shl1(a_, to_); + + if (cmp(to_, m_) >= 0) { + _subFrom(to_, m_); } } } - function modmulAssignTo( + function moddiv( uint256 call_, - uint256 to_, uint256 a_, uint256 b_, uint256 m_ - ) internal view { + ) internal view returns (uint256 r_) { unchecked { - _mul(a_, b_, call_ + 0x60); + r_ = modinv(call_, b_, m_); + + _mul(a_, r_, call_ + 0x60); assembly { mstore(call_, 0x60) @@ -385,7 +339,7 @@ library U384 { 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, r_, 0x40)) } } } @@ -410,59 +364,27 @@ library U384 { } } - function moddiv( - uint256 call_, - uint256 a_, - uint256 b_, - uint256 m_ - ) internal view returns (uint256 r_) { + function mod(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { unchecked { r_ = _allocate(SHORT_ALLOCATION); - _sub(m_, init(2), call_ + 0xA0); - assembly { mstore(call_, 0x40) - mstore(add(0x20, 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(0xE0, call_), mload(m_)) - mstore(add(0x0100, call_), mload(add(m_, 0x20))) + mstore(add(0x60, call_), mload(a_)) + mstore(add(0x80, call_), mload(add(a_, 0x20))) + mstore(add(0xA0, call_), 0x01) + mstore(add(0xC0, call_), mload(m_)) + mstore(add(0xE0, call_), mload(add(m_, 0x20))) - pop(staticcall(gas(), 0x5, call_, 0x0120, r_, 0x40)) + pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) } - return modmul(call_, a_, r_, m_); - } - } - - function add(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { - unchecked { - r_ = _allocate(SHORT_ALLOCATION); - - _add(a_, b_, r_); - - return r_; - } - } - - function sub(uint256 a_, uint256 b_) internal pure returns (uint256 r_) { - unchecked { - r_ = _allocate(SHORT_ALLOCATION); - - _sub(a_, b_, r_); - return r_; } } - 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_) { unchecked { uint256 bytesHandler_ = _allocate(LONG_ALLOCATION); @@ -479,66 +401,23 @@ library U384 { } } - function modshl1(uint256 call_, uint256 a_, uint256 m_) internal view returns (uint256 r_) { - unchecked { - r_ = _allocate(SHORT_ALLOCATION); - - _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))) - - pop(staticcall(gas(), 0x5, call_, 0x0100, r_, 0x40)) - } - } - } - - function modshl1Assign(uint256 call_, uint256 a_, uint256 m_) internal view { - 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))) - - pop(staticcall(gas(), 0x5, call_, 0x0100, a_, 0x40)) - } - } - } - - function modshl1AssignTo(uint256 call_, uint256 to_, uint256 a_, uint256 m_) internal view { - 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))) + function _shl1(uint256 a_, uint256 r_) internal pure { + assembly { + let a0_ := mload(a_) + let a1_ := mload(add(a_, 0x20)) - pop(staticcall(gas(), 0x5, call_, 0x0100, to_, 0x40)) - } + mstore(r_, or(shl(1, a0_), shr(255, a1_))) + mstore(add(r_, 0x20), shl(1, a1_)) } } - function _shl1(uint256 a_, uint256 r_) internal pure { + function _shl1To(uint256 a_) internal pure { 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_)) + mstore(a_, or(shl(1, a0_), shr(255, a1_))) + mstore(add(a_, 0x20), shl(1, a1_)) } } @@ -570,6 +449,34 @@ library U384 { } } + function _subFrom(uint256 a_, uint256 b_) private pure { + assembly { + let aWord_ := mload(add(a_, 0x20)) + let diff_ := sub(aWord_, mload(add(b_, 0x20))) + + mstore(add(a_, 0x20), diff_) + + diff_ := gt(diff_, aWord_) + diff_ := sub(sub(mload(a_), mload(b_)), diff_) + + mstore(a_, diff_) + } + } + + function _addTo(uint256 a_, uint256 b_) private pure { + assembly { + let aWord_ := mload(add(a_, 0x20)) + let sum_ := add(aWord_, mload(add(b_, 0x20))) + + mstore(add(a_, 0x20), sum_) + + sum_ := gt(aWord_, sum_) + sum_ := add(sum_, add(mload(a_), mload(b_))) + + mstore(a_, sum_) + } + } + function _mul(uint256 a_, uint256 b_, uint256 r_) private view { assembly { let a0_ := mload(a_)