Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- P256Verifier
- Optimization enabled
- true
- Compiler version
- v0.8.30+commit.73712a01
- Optimization runs
- 200
- EVM Version
- prague
- Verified at
- 2026-06-23T13:31:53.509169Z
node_modules/p256-verifier/src/P256Verifier.sol
// SPDX-License-Identifier: MIT
// Force a specific Solidity version for reproducibility.
pragma solidity ^0.8.20;
/**
* This contract verifies P256 (secp256r1) signatures. It matches the exact
* interface specified in the EIP-7212 precompile, allowing it to be used as a
* fallback. It's based on Ledger's optimized implementation:
* https://github.com/rdubois-crypto/FreshCryptoLib/tree/master/solidity
**/
contract P256Verifier {
struct CompDoubleZZ {
uint256 comp_U;
uint256 comp_V;
uint256 comp_W;
uint256 comp_S;
uint256 comp_M;
}
struct CompDaddAffine {
uint256 comp_P;
uint256 comp_PP;
uint256 comp_PPP;
uint256 comp_Q;
uint256 comp_R;
}
/**
* Precompiles don't use a function signature. The first byte of callldata
* is the first byte of an input argument. In this case:
*
* input[ 0: 32] = signed data hash
* input[ 32: 64] = signature r
* input[ 64: 96] = signature s
* input[ 96:128] = public key x
* input[128:160] = public key y
*
* result[ 0: 32] = 0x00..00 (invalid) or 0x00..01 (valid)
*
* For details, see https://eips.ethereum.org/EIPS/eip-7212
*/
fallback(bytes calldata input) external returns (bytes memory) {
if (input.length != 160) {
return abi.encodePacked(uint256(0));
}
bytes32 hash = bytes32(input[0:32]);
uint256 r = uint256(bytes32(input[32:64]));
uint256 s = uint256(bytes32(input[64:96]));
uint256 x = uint256(bytes32(input[96:128]));
uint256 y = uint256(bytes32(input[128:160]));
uint256 ret = ecdsa_verify(hash, r, s, [x, y]) ? 1 : 0;
return abi.encodePacked(ret);
}
// Parameters for the sec256r1 (P256) elliptic curve
// Curve prime field modulus
uint256 constant p =
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;
// Short weierstrass first coefficient
uint256 constant a = // The assumption a == -3 (mod p) is used throughout the codebase
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC;
// Short weierstrass second coefficient
uint256 constant b =
0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B;
// Generating point affine coordinates
uint256 constant GX =
0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296;
uint256 constant GY =
0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5;
// Curve order (number of points)
uint256 constant n =
0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551;
// -2 mod p constant, used to speed up inversion and doubling (avoid negation)
uint256 constant minus_2modp =
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFD;
// -2 mod n constant, used to speed up inversion
uint256 constant minus_2modn =
0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254F;
/**
* @dev ECDSA verification given signature and public key.
*/
function ecdsa_verify(
bytes32 message_hash,
uint256 r,
uint256 s,
uint256[2] memory pubKey
) private view returns (bool) {
// Check r and s are in the scalar field
if (r == 0 || r >= n || s == 0 || s >= n) {
return false;
}
if (!ecAff_isValidPubkey(pubKey[0], pubKey[1])) {
return false;
}
uint256 sInv = nModInv(s);
uint256 scalar_u = mulmod(uint256(message_hash), sInv, n); // (h * s^-1) in scalar field
uint256 scalar_v = mulmod(r, sInv, n); // (r * s^-1) in scalar field
uint256 r_x = ecZZ_mulmuladd(
pubKey[0],
pubKey[1],
scalar_u,
scalar_v
);
return r_x % n == r;
}
/**
* @dev Check if a point in affine coordinates is on the curve
* Reject 0 point at infinity.
*/
function ecAff_isValidPubkey(
uint256 x,
uint256 y
) internal pure returns (bool) {
if (x >= p || y >= p || (x == 0 && y == 0)) {
return false;
}
return ecAff_satisfiesCurveEqn(x, y);
}
function ecAff_satisfiesCurveEqn(
uint256 x,
uint256 y
) internal pure returns (bool) {
uint256 LHS = mulmod(y, y, p); // y^2
uint256 RHS = addmod(mulmod(mulmod(x, x, p), x, p), mulmod(a, x, p), p); // x^3 + a x
RHS = addmod(RHS, b, p); // x^3 + a*x + b
return LHS == RHS;
}
/**
* @dev Computation of uG + vQ using Strauss-Shamir's trick, G basepoint, Q public key
* returns tuple of (x coordinate of uG + vQ, boolean that is false if internal precompile staticcall fail)
* Strauss-Shamir is described well in https://stackoverflow.com/a/50994362
*/
function ecZZ_mulmuladd(
uint256 QX,
uint256 QY, // affine rep for input point Q
uint256 scalar_u,
uint256 scalar_v
) internal view returns (uint256 X) {
uint256 zz = 1;
uint256 zzz = 1;
uint256 Y;
uint256 HX;
uint256 HY;
if (scalar_u == 0 && scalar_v == 0) return 0;
// H = g + Q
(HX, HY) = ecAff_add(GX, GY, QX, QY);
int256 index = 255;
uint256 bitpair;
// Find the first bit index that's active in either scalar_u or scalar_v.
while(index >= 0) {
bitpair = compute_bitpair(uint256(index), scalar_u, scalar_v);
index--;
if (bitpair != 0) break;
}
// initialise (X, Y) depending on the first active bitpair.
// invariant(bitpair != 0); // bitpair == 0 is only possible if u and v are 0.
if (bitpair == 1) {
(X, Y) = (GX, GY);
} else if (bitpair == 2) {
(X, Y) = (QX, QY);
} else if (bitpair == 3) {
(X, Y) = (HX, HY);
}
uint256 TX;
uint256 TY;
while(index >= 0) {
(X, Y, zz, zzz) = ecZZ_double_zz(X, Y, zz, zzz);
bitpair = compute_bitpair(uint256(index), scalar_u, scalar_v);
index--;
if (bitpair == 0) {
continue;
} else if (bitpair == 1) {
(TX, TY) = (GX, GY);
} else if (bitpair == 2) {
(TX, TY) = (QX, QY);
} else {
(TX, TY) = (HX, HY);
}
(X, Y, zz, zzz) = ecZZ_dadd_affine(X, Y, zz, zzz, TX, TY);
}
uint256 zzInv = pModInv(zz); // If zz = 0, zzInv = 0.
X = mulmod(X, zzInv, p); // X/zz
}
/**
* @dev Compute the bits at `index` of u and v and return
* them as 2 bit concatenation. The bit at index 0 is on
* if the `index`th bit of scalar_u is on and the bit at
* index 1 is on if the `index`th bit of scalar_v is on.
* Examples:
* - compute_bitpair(0, 1, 1) == 3
* - compute_bitpair(0, 1, 0) == 1
* - compute_bitpair(0, 0, 1) == 2
*/
function compute_bitpair(uint256 index, uint256 scalar_u, uint256 scalar_v) internal pure returns (uint256 ret) {
ret = (((scalar_v >> index) & 1) << 1) + ((scalar_u >> index) & 1);
}
/**
* @dev Add two elliptic curve points in affine coordinates
* Assumes points are on the EC
*/
function ecAff_add(
uint256 x1,
uint256 y1,
uint256 x2,
uint256 y2
) internal view returns (uint256, uint256) {
// invariant(ecAff_IsZero(x1, y1) || ecAff_isOnCurve(x1, y1));
// invariant(ecAff_IsZero(x2, y2) || ecAff_isOnCurve(x2, y2));
uint256 zz1;
uint256 zzz1;
if (ecAff_IsInf(x1, y1)) return (x2, y2);
if (ecAff_IsInf(x2, y2)) return (x1, y1);
(x1, y1, zz1, zzz1) = ecZZ_dadd_affine(x1, y1, 1, 1, x2, y2);
return ecZZ_SetAff(x1, y1, zz1, zzz1);
}
/**
* @dev Check if a point is the infinity point in affine rep.
* Assumes point is on the EC or is the point at infinity.
*/
function ecAff_IsInf(
uint256 x,
uint256 y
) internal pure returns (bool flag) {
// invariant((x == 0 && y == 0) || ecAff_isOnCurve(x, y));
return (x == 0 && y == 0);
}
/**
* @dev Check if a point is the infinity point in ZZ rep.
* Assumes point is on the EC or is the point at infinity.
*/
function ecZZ_IsInf(
uint256 zz,
uint256 zzz
) internal pure returns (bool flag) {
// invariant((zz == 0 && zzz == 0) || ecAff_isOnCurve(x, y) for affine
// form of the point)
return (zz == 0 && zzz == 0);
}
/**
* @dev Add a ZZ point to an affine point and return as ZZ rep
* Uses madd-2008-s and mdbl-2008-s internally
* https://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz-3.html#addition-madd-2008-s
* Matches https://github.com/supranational/blst/blob/9c87d4a09d6648e933c818118a4418349804ce7f/src/ec_ops.h#L705 closely
* Handles points at infinity gracefully
*/
function ecZZ_dadd_affine(
uint256 x1,
uint256 y1,
uint256 zz1,
uint256 zzz1,
uint256 x2,
uint256 y2
) internal pure returns (uint256 x3, uint256 y3, uint256 zz3, uint256 zzz3) {
if (ecAff_IsInf(x2, y2)) { // (X2, Y2) is point at infinity
if (ecZZ_IsInf(zz1, zzz1)) return ecZZ_PointAtInf();
return (x1, y1, zz1, zzz1);
} else if (ecZZ_IsInf(zz1, zzz1)) { // (X1, Y1) is point at infinity
return (x2, y2, 1, 1);
}
CompDaddAffine memory comp;
comp.comp_R = addmod(mulmod(y2, zzz1, p), p - y1, p); // R = S2 - y1 = y2*zzz1 - y1
comp.comp_P = addmod(mulmod(x2, zz1, p), p - x1, p); // P = U2 - x1 = x2*zz1 - x1
if (comp.comp_P != 0) { // X1 != X2
// invariant(x1 != x2);
comp.comp_PP = mulmod(comp.comp_P, comp.comp_P, p); // PP = P^2
comp.comp_PPP = mulmod(comp.comp_PP, comp.comp_P, p); // PPP = P*PP
zz3 = mulmod(zz1, comp.comp_PP, p); //// ZZ3 = ZZ1*PP
zzz3 = mulmod(zzz1, comp.comp_PPP, p); //// ZZZ3 = ZZZ1*PPP
comp.comp_Q = mulmod(x1, comp.comp_PP, p); // Q = X1*PP
x3 = addmod(
addmod(mulmod(comp.comp_R, comp.comp_R, p), p - comp.comp_PPP, p), // (R^2) + (-PPP)
mulmod(minus_2modp, comp.comp_Q, p), // (-2)*(Q)
p
); // R^2 - PPP - 2*Q
y3 = addmod(
mulmod(addmod(comp.comp_Q, p - x3, p), comp.comp_R, p), //(Q+(-x3))*R
mulmod(p - y1, comp.comp_PPP, p), // (-y1)*PPP
p
); // R*(Q-x3) - y1*PPP
} else if (comp.comp_R == 0) { // X1 == X2 and Y1 == Y2
// invariant(x1 == x2 && y1 == y2);
// Must be affine because (X2, Y2) is affine.
(x3, y3, zz3, zzz3) = ecZZ_double_affine(x2, y2);
} else { // X1 == X2 and Y1 == -Y2
// invariant(x1 == x2 && y1 == p - y2);
(x3, y3, zz3, zzz3) = ecZZ_PointAtInf();
}
return (x3, y3, zz3, zzz3);
}
/**
* @dev Double a ZZ point
* Uses http://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1
* Handles point at infinity gracefully
*/
function ecZZ_double_zz(uint256 x1,
uint256 y1, uint256 zz1, uint256 zzz1) internal pure returns (uint256, uint256, uint256, uint256) {
if (ecZZ_IsInf(zz1, zzz1)) return ecZZ_PointAtInf();
CompDoubleZZ memory comp;
comp.comp_U = mulmod(2, y1, p); // U = 2*Y1
comp.comp_V = mulmod(comp.comp_U, comp.comp_U, p); // V = U^2
comp.comp_W = mulmod(comp.comp_U, comp.comp_V, p); // W = U*V
comp.comp_S = mulmod(x1, comp.comp_V, p); // S = X1*V
comp.comp_M = addmod(mulmod(3, mulmod(x1, x1, p), p), mulmod(a, mulmod(zz1, zz1, p), p), p); //M = 3*(X1)^2 + a*(zz1)^2
uint256 x3 = addmod(mulmod(comp.comp_M, comp.comp_M, p), mulmod(minus_2modp, comp.comp_S, p), p); // M^2 + (-2)*S
return(
x3, // M^2 + (-2)*S
addmod(mulmod(comp.comp_M, addmod(comp.comp_S, p - x3, p), p), mulmod(p - comp.comp_W, y1, p), p), // M*(S+(-X3)) + (-W)*Y1
mulmod(comp.comp_V, zz1, p), // V*ZZ1
mulmod(comp.comp_W, zzz1, p) // W*ZZZ1
);
}
/**
* @dev Double an affine point and return as a ZZ point
* Uses http://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-mdbl-2008-s-1
* Handles point at infinity gracefully
*/
function ecZZ_double_affine(uint256 x1,
uint256 y1) internal pure returns (uint256 x3, uint256 y3, uint256 zz3, uint256 zzz3) {
if (ecAff_IsInf(x1, y1)) return ecZZ_PointAtInf();
uint256 comp_U = mulmod(2, y1, p); // U = 2*Y1
zz3 = mulmod(comp_U, comp_U, p); // V = U^2 = zz3
zzz3 = mulmod(comp_U, zz3, p); // W = U*V = zzz3
uint256 comp_S = mulmod(x1, zz3, p); // S = X1*V
uint256 comp_M = addmod(mulmod(3, mulmod(x1, x1, p), p), a, p); // M = 3*(X1)^2 + a
x3 = addmod(mulmod(comp_M, comp_M, p), mulmod(minus_2modp, comp_S, p), p); // M^2 + (-2)*S
y3 = addmod(mulmod(comp_M, addmod(comp_S, p - x3, p), p), mulmod(p - zzz3, y1, p), p); // M*(S+(-X3)) + (-W)*Y1
}
/**
* @dev Convert from ZZ rep to affine rep
* Assumes (zz)^(3/2) == zzz (i.e. zz == z^2 and zzz == z^3)
* See https://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz-3.html
*/
function ecZZ_SetAff(
uint256 x,
uint256 y,
uint256 zz,
uint256 zzz
) internal view returns (uint256 x1, uint256 y1) {
if(ecZZ_IsInf(zz, zzz)) {
(x1, y1) = ecAffine_PointAtInf();
return (x1, y1);
}
uint256 zzzInv = pModInv(zzz); // 1 / zzz
uint256 zInv = mulmod(zz, zzzInv, p); // 1 / z
uint256 zzInv = mulmod(zInv, zInv, p); // 1 / zz
// invariant(mulmod(FCL_pModInv(zInv), FCL_pModInv(zInv), p) == zz)
// invariant(mulmod(mulmod(FCL_pModInv(zInv), FCL_pModInv(zInv), p), FCL_pModInv(zInv), p) == zzz)
x1 = mulmod(x, zzInv, p); // X / zz
y1 = mulmod(y, zzzInv, p); // y = Y / zzz
}
/**
* @dev Point at infinity in ZZ rep
*/
function ecZZ_PointAtInf() internal pure returns (uint256, uint256, uint256, uint256) {
return (0, 0, 0, 0);
}
/**
* @dev Point at infinity in affine rep
*/
function ecAffine_PointAtInf() internal pure returns (uint256, uint256) {
return (0, 0);
}
/**
* @dev u^-1 mod n
*/
function nModInv(uint256 u) internal view returns (uint256) {
return modInv(u, n, minus_2modn);
}
/**
* @dev u^-1 mod p
*/
function pModInv(uint256 u) internal view returns (uint256) {
return modInv(u, p, minus_2modp);
}
/**
* @dev u^-1 mod f = u^(phi(f) - 1) mod f = u^(f-2) mod f for prime f
* by Fermat's little theorem, compute u^(f-2) mod f using modexp precompile
* Assume f != 0. If u is 0, then u^-1 mod f is undefined mathematically,
* but this function returns 0.
*/
function modInv(uint256 u, uint256 f, uint256 minus_2modf) internal view returns (uint256 result) {
// invariant(f != 0);
// invariant(f prime);
// This seems like a relatively standard way to use this precompile:
// https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3298/files#diff-489d4519a087ca2c75be3315b673587abeca3b302f807643e97efa7de8cb35a5R427
(bool success, bytes memory ret) = (address(0x05).staticcall(abi.encode(32, 32, 32, u, minus_2modf, f)));
assert(success); // precompile should never fail on regular EVM environments
result = abi.decode(ret, (uint256));
}
}
Compiler Settings
{"viaIR":false,"remappings":["openzeppelin/=node_modules/@openzeppelin/","@openzeppelin/=node_modules/@openzeppelin/","@openzeppelin-upgrades/contracts/=node_modules/@openzeppelin/contracts-upgradeable/","@risc0/contracts/=node_modules/risc0-ethereum/contracts/src/","@solady/=node_modules/solady/","solady/src/=node_modules/solady/src/","solady/utils/=node_modules/solady/src/utils/","@optimism/=node_modules/optimism/","@sp1-contracts/=node_modules/sp1-contracts/contracts/","forge-std/=node_modules/forge-std/","@p256-verifier/contracts/=node_modules/p256-verifier/src/","@eth-fabric/urc/=node_modules/urc/src/","ds-test/=node_modules/ds-test/","src/=contracts/","test/=test/","script/=script/","optimism/=node_modules/optimism/","p256-verifier/=node_modules/p256-verifier/","risc0-ethereum/=node_modules/risc0-ethereum/","sp1-contracts/=node_modules/sp1-contracts/","urc/=node_modules/urc/"],"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{},"evmVersion":"prague"}
Contract ABI
[{"type":"fallback","stateMutability":"nonpayable"}]
Contract Creation Code
0x6080604052348015600e575f5ffd5b50610e988061001c5f395ff3fe608060405234801561000f575f5ffd5b505f36606060a0821461003d57604080515f602082015201604051602081830303815290604052905061011e565b5f61004b6020828587610d49565b61005491610d70565b90505f610065604060208688610d49565b61006e91610d70565b90505f61007f606060408789610d49565b61008891610d70565b90505f61009960806060888a610d49565b6100a291610d70565b90505f6100b360a06080898b610d49565b6100bc91610d70565b5f1c90505f6100e1868686604051806040016040528088815260200187815250610129565b6100eb575f6100ee565b60015b60ff1690508060405160200161010691815260200190565b60405160208183030381529060405296505050505050505b915050805190602001f35b5f83158061014457505f516020610e435f395f51905f528410155b8061014d575082155b8061016557505f516020610e435f395f51905f528310155b1561017157505f6101f9565b815160208301516101829190610201565b61018d57505f6101f9565b5f6101978461025e565b90505f5f516020610e435f395f51905f5282880990505f5f516020610e435f395f51905f52838809855160208701519192505f916101d791908585610297565b9050876101f15f516020610e435f395f51905f5283610d8d565b149450505050505b949350505050565b5f600160601b63ffffffff60c01b03198310158061022d5750600160601b63ffffffff60c01b03198210155b8061023f57508215801561023f575081155b1561024b57505f610258565b61025583836104aa565b90505b92915050565b5f610258825f516020610e435f395f51905f527fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f610549565b5f600180828080871580156102aa575086155b156102bc575f955050505050506101f9565b6103087f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2967f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f58c8c61060b565b909250905060ff5f5b5f821261033957610323828b8b61067c565b90508161032f81610dc0565b9250508015610311575b8060010361038c577f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29697507f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f594506103b2565b8060020361039f578b97508a94506103b2565b806003036103b257838380965081995050505b5f5f5b5f8412610479576103c88a888b8b610696565b929c509a5090985096506103dd848d8d61067c565b9250836103e981610dc0565b94505082156103b5578260010361044457507f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29690507f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f561045c565b8260020361045657508c90508b61045c565b50849050835b61046a8a888b8b8686610885565b929c509a5090985096506103b5565b5f6104838a610b38565b9050600160601b63ffffffff60c01b0319818c099f9e505050505050505050505050505050565b5f80600160601b63ffffffff60c01b031983840990505f600160601b63ffffffff60c01b031980866003600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b031987600160601b63ffffffff60c01b0319898a0909089050600160601b63ffffffff60c01b03197f5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b820891909114949350505050565b60408051602081810181905291810182905260608101919091526080810184905260a0810182905260c081018390525f908190819060059060e00160408051601f198184030181529082905261059e91610ddb565b5f60405180830381855afa9150503d805f81146105d6576040519150601f19603f3d011682016040523d82523d5f602084013e6105db565b606091505b5091509150816105ed576105ed610df1565b808060200190518101906106019190610e05565b9695505050505050565b5f5f5f5f6106198888610b63565b1561062b578585935093505050610673565b6106358686610b63565b15610647578787935093505050610673565b61065688886001808a8a610885565b929a509098509250905061066c88888484610b74565b9350935050505b94509492505050565b5f6101f9600184861c811690600285881c90911b16610e1c565b5f5f5f5f6106a48686610b63565b156106b957505f92508291508190508061087a565b6106e66040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b600160601b63ffffffff60c01b0319886002098152600160601b63ffffffff60c01b0319815180096020820152600160601b63ffffffff60c01b031960208201518251096040820152600160601b63ffffffff60c01b031981602001518a096060820152600160601b63ffffffff60c01b031980600160601b63ffffffff60c01b0319898a096003600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b0319808c8d096003090860808201525f600160601b63ffffffff60c01b03198083606001516002600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b03196080850151800908905080600160601b63ffffffff60c01b0319808b8560400151600160601b63ffffffff60c01b031961080d9190610e2f565b09600160601b63ffffffff60c01b03198061083686600160601b63ffffffff60c01b0319610e2f565b87606001510886608001510908600160601b63ffffffff60c01b03198a856020015109600160601b63ffffffff60c01b03198a866040015109955095509550955050505b945094509450949050565b5f5f5f5f6108938686610b63565b156108c7576108a28888610b63565b156108b757505f925082915081905080610b2b565b5088925087915086905085610b2b565b6108d18888610b63565b156108e757508492508391506001905080610b2b565b6109146040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b600160601b63ffffffff60c01b031961093b8b600160601b63ffffffff60c01b0319610e2f565b600160601b63ffffffff60c01b03198a8909086080820152600160601b63ffffffff60c01b031961097a8c600160601b63ffffffff60c01b0319610e2f565b600160601b63ffffffff60c01b03198b8a090880825215610af857600160601b63ffffffff60c01b031981518009602082018190528151600160601b63ffffffff60c01b031991096040820152600160601b63ffffffff60c01b031981602001518a099250600160601b63ffffffff60c01b0319816040015189099150600160601b63ffffffff60c01b031981602001518c096060820152600160601b63ffffffff60c01b03198082606001516002600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b03196040840151610a6690600160601b63ffffffff60c01b0319610e2f565b600160601b63ffffffff60c01b03196080860151800908089450600160601b63ffffffff60c01b0319806040830151610aad8d600160601b63ffffffff60c01b0319610e2f565b09600160601b63ffffffff60c01b03196080840151600160601b63ffffffff60c01b0319610ae98a600160601b63ffffffff60c01b0319610e2f565b86606001510809089350610b29565b80608001515f03610b1c57610b0d8787610bf9565b92975090955093509150610b29565b5f94508493508392508291505b505b9650965096509692505050565b5f61025882600160601b63ffffffff60c01b03196002600160601b0363ffffffff60c01b0319610549565b5f8215801561025557505015919050565b5f5f610b808484610b63565b15610b8f57505f905080610673565b5f610b9984610b38565b90505f600160601b63ffffffff60c01b031982870990505f600160601b63ffffffff60c01b03198283099050600160601b63ffffffff60c01b0319818a099450600160601b63ffffffff60c01b0319838909935050505094509492505050565b5f5f5f5f610c078686610b63565b15610c1c57505f925082915081905080610d40565b5f600160601b63ffffffff60c01b0319866002099050600160601b63ffffffff60c01b03198182099250600160601b63ffffffff60c01b031983820991505f600160601b63ffffffff60c01b031984890990505f600160601b63ffffffff60c01b03196003600160601b0363ffffffff60c01b0319600160601b63ffffffff60c01b0319808c8d09600309089050600160601b63ffffffff60c01b031980836002600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b0319838409089650600160601b63ffffffff60c01b03198089610d0c87600160601b63ffffffff60c01b0319610e2f565b09600160601b63ffffffff60c01b031980610d358b600160601b63ffffffff60c01b0319610e2f565b860884090895505050505b92959194509250565b5f5f85851115610d57575f5ffd5b83861115610d63575f5ffd5b5050820193919092039150565b80356020831015610258575f19602084900360031b1b1692915050565b5f82610da757634e487b7160e01b5f52601260045260245ffd5b500690565b634e487b7160e01b5f52601160045260245ffd5b5f600160ff1b8201610dd457610dd4610dac565b505f190190565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52600160045260245ffd5b5f60208284031215610e15575f5ffd5b5051919050565b8082018082111561025857610258610dac565b8181038181111561025857610258610dac56feffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551a264697066735822122015a21e5f4954cd1025230ca8353e983cb4e9ce26024bd92dd4cc7e1cf0c0bdf364736f6c634300081e0033
Deployed ByteCode
0x608060405234801561000f575f5ffd5b505f36606060a0821461003d57604080515f602082015201604051602081830303815290604052905061011e565b5f61004b6020828587610d49565b61005491610d70565b90505f610065604060208688610d49565b61006e91610d70565b90505f61007f606060408789610d49565b61008891610d70565b90505f61009960806060888a610d49565b6100a291610d70565b90505f6100b360a06080898b610d49565b6100bc91610d70565b5f1c90505f6100e1868686604051806040016040528088815260200187815250610129565b6100eb575f6100ee565b60015b60ff1690508060405160200161010691815260200190565b60405160208183030381529060405296505050505050505b915050805190602001f35b5f83158061014457505f516020610e435f395f51905f528410155b8061014d575082155b8061016557505f516020610e435f395f51905f528310155b1561017157505f6101f9565b815160208301516101829190610201565b61018d57505f6101f9565b5f6101978461025e565b90505f5f516020610e435f395f51905f5282880990505f5f516020610e435f395f51905f52838809855160208701519192505f916101d791908585610297565b9050876101f15f516020610e435f395f51905f5283610d8d565b149450505050505b949350505050565b5f600160601b63ffffffff60c01b03198310158061022d5750600160601b63ffffffff60c01b03198210155b8061023f57508215801561023f575081155b1561024b57505f610258565b61025583836104aa565b90505b92915050565b5f610258825f516020610e435f395f51905f527fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f610549565b5f600180828080871580156102aa575086155b156102bc575f955050505050506101f9565b6103087f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2967f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f58c8c61060b565b909250905060ff5f5b5f821261033957610323828b8b61067c565b90508161032f81610dc0565b9250508015610311575b8060010361038c577f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29697507f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f594506103b2565b8060020361039f578b97508a94506103b2565b806003036103b257838380965081995050505b5f5f5b5f8412610479576103c88a888b8b610696565b929c509a5090985096506103dd848d8d61067c565b9250836103e981610dc0565b94505082156103b5578260010361044457507f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29690507f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f561045c565b8260020361045657508c90508b61045c565b50849050835b61046a8a888b8b8686610885565b929c509a5090985096506103b5565b5f6104838a610b38565b9050600160601b63ffffffff60c01b0319818c099f9e505050505050505050505050505050565b5f80600160601b63ffffffff60c01b031983840990505f600160601b63ffffffff60c01b031980866003600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b031987600160601b63ffffffff60c01b0319898a0909089050600160601b63ffffffff60c01b03197f5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b820891909114949350505050565b60408051602081810181905291810182905260608101919091526080810184905260a0810182905260c081018390525f908190819060059060e00160408051601f198184030181529082905261059e91610ddb565b5f60405180830381855afa9150503d805f81146105d6576040519150601f19603f3d011682016040523d82523d5f602084013e6105db565b606091505b5091509150816105ed576105ed610df1565b808060200190518101906106019190610e05565b9695505050505050565b5f5f5f5f6106198888610b63565b1561062b578585935093505050610673565b6106358686610b63565b15610647578787935093505050610673565b61065688886001808a8a610885565b929a509098509250905061066c88888484610b74565b9350935050505b94509492505050565b5f6101f9600184861c811690600285881c90911b16610e1c565b5f5f5f5f6106a48686610b63565b156106b957505f92508291508190508061087a565b6106e66040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b600160601b63ffffffff60c01b0319886002098152600160601b63ffffffff60c01b0319815180096020820152600160601b63ffffffff60c01b031960208201518251096040820152600160601b63ffffffff60c01b031981602001518a096060820152600160601b63ffffffff60c01b031980600160601b63ffffffff60c01b0319898a096003600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b0319808c8d096003090860808201525f600160601b63ffffffff60c01b03198083606001516002600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b03196080850151800908905080600160601b63ffffffff60c01b0319808b8560400151600160601b63ffffffff60c01b031961080d9190610e2f565b09600160601b63ffffffff60c01b03198061083686600160601b63ffffffff60c01b0319610e2f565b87606001510886608001510908600160601b63ffffffff60c01b03198a856020015109600160601b63ffffffff60c01b03198a866040015109955095509550955050505b945094509450949050565b5f5f5f5f6108938686610b63565b156108c7576108a28888610b63565b156108b757505f925082915081905080610b2b565b5088925087915086905085610b2b565b6108d18888610b63565b156108e757508492508391506001905080610b2b565b6109146040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b600160601b63ffffffff60c01b031961093b8b600160601b63ffffffff60c01b0319610e2f565b600160601b63ffffffff60c01b03198a8909086080820152600160601b63ffffffff60c01b031961097a8c600160601b63ffffffff60c01b0319610e2f565b600160601b63ffffffff60c01b03198b8a090880825215610af857600160601b63ffffffff60c01b031981518009602082018190528151600160601b63ffffffff60c01b031991096040820152600160601b63ffffffff60c01b031981602001518a099250600160601b63ffffffff60c01b0319816040015189099150600160601b63ffffffff60c01b031981602001518c096060820152600160601b63ffffffff60c01b03198082606001516002600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b03196040840151610a6690600160601b63ffffffff60c01b0319610e2f565b600160601b63ffffffff60c01b03196080860151800908089450600160601b63ffffffff60c01b0319806040830151610aad8d600160601b63ffffffff60c01b0319610e2f565b09600160601b63ffffffff60c01b03196080840151600160601b63ffffffff60c01b0319610ae98a600160601b63ffffffff60c01b0319610e2f565b86606001510809089350610b29565b80608001515f03610b1c57610b0d8787610bf9565b92975090955093509150610b29565b5f94508493508392508291505b505b9650965096509692505050565b5f61025882600160601b63ffffffff60c01b03196002600160601b0363ffffffff60c01b0319610549565b5f8215801561025557505015919050565b5f5f610b808484610b63565b15610b8f57505f905080610673565b5f610b9984610b38565b90505f600160601b63ffffffff60c01b031982870990505f600160601b63ffffffff60c01b03198283099050600160601b63ffffffff60c01b0319818a099450600160601b63ffffffff60c01b0319838909935050505094509492505050565b5f5f5f5f610c078686610b63565b15610c1c57505f925082915081905080610d40565b5f600160601b63ffffffff60c01b0319866002099050600160601b63ffffffff60c01b03198182099250600160601b63ffffffff60c01b031983820991505f600160601b63ffffffff60c01b031984890990505f600160601b63ffffffff60c01b03196003600160601b0363ffffffff60c01b0319600160601b63ffffffff60c01b0319808c8d09600309089050600160601b63ffffffff60c01b031980836002600160601b0363ffffffff60c01b031909600160601b63ffffffff60c01b0319838409089650600160601b63ffffffff60c01b03198089610d0c87600160601b63ffffffff60c01b0319610e2f565b09600160601b63ffffffff60c01b031980610d358b600160601b63ffffffff60c01b0319610e2f565b860884090895505050505b92959194509250565b5f5f85851115610d57575f5ffd5b83861115610d63575f5ffd5b5050820193919092039150565b80356020831015610258575f19602084900360031b1b1692915050565b5f82610da757634e487b7160e01b5f52601260045260245ffd5b500690565b634e487b7160e01b5f52601160045260245ffd5b5f600160ff1b8201610dd457610dd4610dac565b505f190190565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52600160045260245ffd5b5f60208284031215610e15575f5ffd5b5051919050565b8082018082111561025857610258610dac565b8181038181111561025857610258610dac56feffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551a264697066735822122015a21e5f4954cd1025230ca8353e983cb4e9ce26024bd92dd4cc7e1cf0c0bdf364736f6c634300081e0033