diff --git a/.gas-snapshot b/.gas-snapshot index eef83797..32a6dadf 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,751 +1,758 @@ -AccessControlInvariants:invariantGetRoleAdmin() (runs: 256, calls: 3840, reverts: 3840) -AccessControlInvariants:invariantHasRole() (runs: 256, calls: 3840, reverts: 3840) -AccessControlTest:testFuzzGrantRoleAdminRoleSuccess(address) (runs: 256, μ: 44090, ~: 44090) -AccessControlTest:testFuzzGrantRoleMultipleTimesSuccess(address) (runs: 256, μ: 50007, ~: 50007) -AccessControlTest:testFuzzGrantRoleNonAdmin(address,address) (runs: 256, μ: 16544, ~: 16544) -AccessControlTest:testFuzzGrantRoleSuccess(address) (runs: 256, μ: 44156, ~: 44156) -AccessControlTest:testFuzzRenounceRoleMultipleTimesSuccess(address) (runs: 256, μ: 46094, ~: 46079) -AccessControlTest:testFuzzRenounceRoleNonMsgSender(address) (runs: 256, μ: 9556, ~: 9556) -AccessControlTest:testFuzzRenounceRoleSuccess(address) (runs: 256, μ: 42015, ~: 42000) -AccessControlTest:testFuzzRevokeRoleMultipleTimesSuccess(address) (runs: 256, μ: 41785, ~: 41769) -AccessControlTest:testFuzzRevokeRoleNonAdmin(address,address) (runs: 256, μ: 16498, ~: 16498) -AccessControlTest:testFuzzRevokeRoleSuccess(address) (runs: 256, μ: 40629, ~: 40613) -AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsGrantRole(address,address) (runs: 256, μ: 76106, ~: 76106) -AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsRevokeRole(address,address) (runs: 256, μ: 101635, ~: 101635) -AccessControlTest:testFuzzSetRoleAdminSuccess(address,address) (runs: 256, μ: 91093, ~: 91093) -AccessControlTest:testGrantRoleAdminRoleSuccess() (gas: 45064) -AccessControlTest:testGrantRoleMultipleTimesSuccess() (gas: 51025) -AccessControlTest:testGrantRoleNonAdmin() (gas: 14998) -AccessControlTest:testGrantRoleSuccess() (gas: 45283) -AccessControlTest:testInitialSetup() (gas: 474709) -AccessControlTest:testRenounceRoleAdminRoleSuccess() (gas: 21004) -AccessControlTest:testRenounceRoleMultipleTimesSuccess() (gas: 46929) -AccessControlTest:testRenounceRoleNonMsgSender() (gas: 10644) -AccessControlTest:testRenounceRoleSuccess() (gas: 42922) -AccessControlTest:testRevokeRoleAdminRoleSuccess() (gas: 25016) -AccessControlTest:testRevokeRoleMultipleTimesSuccess() (gas: 42656) -AccessControlTest:testRevokeRoleNonAdmin() (gas: 15086) -AccessControlTest:testRevokeRoleSuccess() (gas: 41500) -AccessControlTest:testSetRoleAdminPreviousAdminCallsGrantRole() (gas: 78703) -AccessControlTest:testSetRoleAdminPreviousAdminCallsRevokeRole() (gas: 104164) -AccessControlTest:testSetRoleAdminSuccess() (gas: 93519) +AccessControlInvariants:statefulFuzzGetRoleAdmin() (runs: 256, calls: 3840, reverts: 3839) +AccessControlInvariants:statefulFuzzHasRole() (runs: 256, calls: 3840, reverts: 3839) +AccessControlTest:testFuzzGrantRoleAdminRoleSuccess(address) (runs: 256, μ: 44082, ~: 44082) +AccessControlTest:testFuzzGrantRoleMultipleTimesSuccess(address) (runs: 256, μ: 49983, ~: 49983) +AccessControlTest:testFuzzGrantRoleNonAdmin(address,address) (runs: 256, μ: 16471, ~: 16471) +AccessControlTest:testFuzzGrantRoleSuccess(address) (runs: 256, μ: 44148, ~: 44148) +AccessControlTest:testFuzzRenounceRoleMultipleTimesSuccess(address) (runs: 256, μ: 45995, ~: 45980) +AccessControlTest:testFuzzRenounceRoleNonMsgSender(address) (runs: 256, μ: 9483, ~: 9483) +AccessControlTest:testFuzzRenounceRoleSuccess(address) (runs: 256, μ: 41952, ~: 41938) +AccessControlTest:testFuzzRevokeRoleMultipleTimesSuccess(address) (runs: 256, μ: 41758, ~: 41744) +AccessControlTest:testFuzzRevokeRoleNonAdmin(address,address) (runs: 256, μ: 16425, ~: 16425) +AccessControlTest:testFuzzRevokeRoleSuccess(address) (runs: 256, μ: 40590, ~: 40576) +AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsGrantRole(address,address) (runs: 256, μ: 76002, ~: 76002) +AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsRevokeRole(address,address) (runs: 256, μ: 101546, ~: 101546) +AccessControlTest:testFuzzSetRoleAdminSuccess(address,address) (runs: 256, μ: 91046, ~: 91046) +AccessControlTest:testGrantRoleAdminRoleSuccess() (gas: 44827) +AccessControlTest:testGrantRoleMultipleTimesSuccess() (gas: 50772) +AccessControlTest:testGrantRoleNonAdmin() (gas: 14696) +AccessControlTest:testGrantRoleSuccess() (gas: 45046) +AccessControlTest:testInitialSetup() (gas: 479352) +AccessControlTest:testRenounceRoleAdminRoleSuccess() (gas: 20935) +AccessControlTest:testRenounceRoleMultipleTimesSuccess() (gas: 46648) +AccessControlTest:testRenounceRoleNonMsgSender() (gas: 10342) +AccessControlTest:testRenounceRoleSuccess() (gas: 42677) +AccessControlTest:testRevokeRoleAdminRoleSuccess() (gas: 24912) +AccessControlTest:testRevokeRoleMultipleTimesSuccess() (gas: 42447) +AccessControlTest:testRevokeRoleNonAdmin() (gas: 14784) +AccessControlTest:testRevokeRoleSuccess() (gas: 41280) +AccessControlTest:testSetRoleAdminPreviousAdminCallsGrantRole() (gas: 78141) +AccessControlTest:testSetRoleAdminPreviousAdminCallsRevokeRole() (gas: 103617) +AccessControlTest:testSetRoleAdminSuccess() (gas: 93014) AccessControlTest:testSupportsInterfaceInvalidInterfaceId() (gas: 8378) AccessControlTest:testSupportsInterfaceInvalidInterfaceIdGasCost() (gas: 9211) AccessControlTest:testSupportsInterfaceSuccess() (gas: 9527) AccessControlTest:testSupportsInterfaceSuccessGasCost() (gas: 9167) -Base64Test:testDataLengthMismatch() (gas: 15844) -Base64Test:testDecodeEmptyString() (gas: 7914) -Base64Test:testDecodeSafeUrl() (gas: 322086) -Base64Test:testDecodeSentence() (gas: 811907) -Base64Test:testDecodeSingleCharacter() (gas: 153350) -Base64Test:testDecodeWithDoublePadding() (gas: 225773) -Base64Test:testDecodeWithNoPadding() (gas: 178995) -Base64Test:testDecodeWithSinglePadding() (gas: 189251) -Base64Test:testEncodeEmptyString() (gas: 9100) -Base64Test:testEncodeSafeUrl() (gas: 83259) -Base64Test:testEncodeSentence() (gas: 110695) -Base64Test:testEncodeSingleCharacter() (gas: 65663) -Base64Test:testEncodeWithDoublePadding() (gas: 71302) -Base64Test:testEncodeWithNoPadding() (gas: 70033) -Base64Test:testEncodeWithSinglePadding() (gas: 71405) -BatchDistributorInvariants:invariantNoEtherBalance() (runs: 256, calls: 3840, reverts: 3827) -BatchDistributorInvariants:invariantNoTokenBalance() (runs: 256, calls: 3840, reverts: 3827) -BatchDistributorTest:testDistributeEtherMultipleAddressesSuccess() (gas: 153468) -BatchDistributorTest:testDistributeEtherOneAddressSuccess() (gas: 79162) -BatchDistributorTest:testDistributeEtherRevertWithInsufficientFunds() (gas: 83137) -BatchDistributorTest:testDistributeEtherRevertWithNoFallbackFunctionForMsgSender() (gas: 158995) -BatchDistributorTest:testDistributeEtherRevertWithNoFallbackFunctionForReceipt() (gas: 54248) -BatchDistributorTest:testDistributeEtherSendsBackExcessiveEther() (gas: 189075) -BatchDistributorTest:testDistributeTokenMultipleAddressesSuccess() (gas: 617661) -BatchDistributorTest:testDistributeTokenOneAddressSuccess() (gas: 579248) -BatchDistributorTest:testDistributeTokenRevertWithInsufficientAllowance() (gas: 574620) -BatchDistributorTest:testDistributeTokenRevertWithInsufficientBalance() (gas: 575406) -BatchDistributorTest:testFuzzDistributeEtherMultipleAddressesSuccess(((address,uint256)[]),uint256) (runs: 256, μ: 1855235, ~: 1871491) -BatchDistributorTest:testFuzzDistributeTokenMultipleAddressesSuccess(((address,uint256)[]),address,uint256) (runs: 256, μ: 1347764, ~: 1322615) -Create2AddressTest:testComputeAddress() (gas: 550584) -Create2AddressTest:testComputeAddressSelf() (gas: 559224) -Create2AddressTest:testFuzzComputeAddress(bytes32,address) (runs: 256, μ: 551179, ~: 551179) -Create2AddressTest:testFuzzComputeAddressSelf(bytes32) (runs: 256, μ: 559245, ~: 559245) -CreateAddressTest:testComputeAddressNonce0x00() (gas: 16530) -CreateAddressTest:testComputeAddressNonce0x7f() (gas: 535247) -CreateAddressTest:testComputeAddressNonceUint16() (gas: 535299) -CreateAddressTest:testComputeAddressNonceUint24() (gas: 535394) -CreateAddressTest:testComputeAddressNonceUint32() (gas: 535356) -CreateAddressTest:testComputeAddressNonceUint40() (gas: 535428) -CreateAddressTest:testComputeAddressNonceUint48() (gas: 535456) -CreateAddressTest:testComputeAddressNonceUint56() (gas: 535484) -CreateAddressTest:testComputeAddressNonceUint64() (gas: 535621) -CreateAddressTest:testComputeAddressNonceUint8() (gas: 535339) -CreateAddressTest:testComputeAddressRevertTooHighNonce() (gas: 10613) -CreateAddressTest:testComputeAddressSelfNonce0x7f() (gas: 539479) -CreateAddressTest:testComputeAddressSelfNonceUint16() (gas: 539700) -CreateAddressTest:testComputeAddressSelfNonceUint24() (gas: 539729) -CreateAddressTest:testComputeAddressSelfNonceUint32() (gas: 539825) -CreateAddressTest:testComputeAddressSelfNonceUint40() (gas: 539854) -CreateAddressTest:testComputeAddressSelfNonceUint48() (gas: 539882) -CreateAddressTest:testComputeAddressSelfNonceUint56() (gas: 539911) -CreateAddressTest:testComputeAddressSelfNonceUint64() (gas: 540028) -CreateAddressTest:testComputeAddressSelfNonceUint8() (gas: 539634) -CreateAddressTest:testComputeAddressSelfRevertTooHighNonce() (gas: 8836) -CreateAddressTest:testFuzzComputeAddressNonce0x7f(uint64,address) (runs: 256, μ: 538292, ~: 538387) -CreateAddressTest:testFuzzComputeAddressNonceUint16(uint64,address) (runs: 256, μ: 537728, ~: 538001) -CreateAddressTest:testFuzzComputeAddressNonceUint24(uint64,address) (runs: 256, μ: 537855, ~: 537978) -CreateAddressTest:testFuzzComputeAddressNonceUint32(uint64,address) (runs: 256, μ: 537880, ~: 537985) -CreateAddressTest:testFuzzComputeAddressNonceUint40(uint64,address) (runs: 256, μ: 537979, ~: 538077) -CreateAddressTest:testFuzzComputeAddressNonceUint48(uint64,address) (runs: 256, μ: 537963, ~: 538061) -CreateAddressTest:testFuzzComputeAddressNonceUint56(uint64,address) (runs: 256, μ: 538002, ~: 538090) -CreateAddressTest:testFuzzComputeAddressNonceUint64(uint64,address) (runs: 256, μ: 538003, ~: 538194) -CreateAddressTest:testFuzzComputeAddressNonceUint8(uint64,address) (runs: 256, μ: 537783, ~: 537852) -CreateAddressTest:testFuzzComputeAddressRevertTooHighNonce(uint256,address) (runs: 256, μ: 12913, ~: 12845) -CreateAddressTest:testFuzzComputeAddressSelfNonce0x7f(uint64) (runs: 256, μ: 544467, ~: 544576) -CreateAddressTest:testFuzzComputeAddressSelfNonceUint16(uint64) (runs: 256, μ: 543688, ~: 543612) -CreateAddressTest:testFuzzComputeAddressSelfNonceUint24(uint64) (runs: 256, μ: 543970, ~: 544066) -CreateAddressTest:testFuzzComputeAddressSelfNonceUint32(uint64) (runs: 256, μ: 544056, ~: 544162) -CreateAddressTest:testFuzzComputeAddressSelfNonceUint40(uint64) (runs: 256, μ: 544065, ~: 544146) -CreateAddressTest:testFuzzComputeAddressSelfNonceUint48(uint64) (runs: 256, μ: 544109, ~: 544220) -CreateAddressTest:testFuzzComputeAddressSelfNonceUint56(uint64) (runs: 256, μ: 544199, ~: 544290) -CreateAddressTest:testFuzzComputeAddressSelfNonceUint64(uint64) (runs: 256, μ: 544238, ~: 544420) -CreateAddressTest:testFuzzComputeAddressSelfNonceUint8(uint64) (runs: 256, μ: 543770, ~: 543857) -CreateAddressTest:testFuzzComputeAddressSelfRevertTooHighNonce(uint256) (runs: 256, μ: 12723, ~: 12684) -ECDSATest:testEthSignedMessageHash() (gas: 8732) -ECDSATest:testFuzzEthSignedMessageHash(string) (runs: 256, μ: 9318, ~: 9312) -ECDSATest:testFuzzRecoverWithInvalidSignature(bytes,string) (runs: 256, μ: 15516, ~: 15518) -ECDSATest:testFuzzRecoverWithTooLongSignature(bytes,string) (runs: 256, μ: 13999, ~: 14002) -ECDSATest:testFuzzRecoverWithValidSignature(string,string) (runs: 256, μ: 22416, ~: 22477) -ECDSATest:testFuzzRecoverWithWrongMessage(string,string,bytes32) (runs: 256, μ: 22435, ~: 22381) -ECDSATest:testFuzzToDataWithIntendedValidatorHash(address,bytes) (runs: 256, μ: 10184, ~: 10170) -ECDSATest:testFuzzToDataWithIntendedValidatorHashSelf(bytes) (runs: 256, μ: 12212, ~: 12195) -ECDSATest:testFuzzToTypedDataHash(string,string) (runs: 256, μ: 9936, ~: 9937) -ECDSATest:testRecoverWith0x00Value() (gas: 15622) -ECDSATest:testRecoverWithArbitraryMessage() (gas: 21344) -ECDSATest:testRecoverWithCorrectVersion() (gas: 22086) -ECDSATest:testRecoverWithInvalidSignature() (gas: 15211) -ECDSATest:testRecoverWithTooHighSValue() (gas: 16537) -ECDSATest:testRecoverWithTooLongSignature() (gas: 13109) -ECDSATest:testRecoverWithTooShortSignature() (gas: 14304) -ECDSATest:testRecoverWithValidSignature() (gas: 21337) -ECDSATest:testRecoverWithWrongMessage() (gas: 21414) -ECDSATest:testRecoverWithWrongVersion() (gas: 15651) -ECDSATest:testToDataWithIntendedValidatorHash() (gas: 11979) -ECDSATest:testToDataWithIntendedValidatorHashSelf() (gas: 12367) -ECDSATest:testToTypedDataHash() (gas: 8823) -EIP712DomainSeparatorTest:testCachedDomainSeparatorV4() (gas: 10440) -EIP712DomainSeparatorTest:testDomainSeparatorV4() (gas: 11715) -EIP712DomainSeparatorTest:testEIP712Domain() (gas: 18648) -EIP712DomainSeparatorTest:testFuzzDomainSeparatorV4(uint8) (runs: 256, μ: 11867, ~: 11890) -EIP712DomainSeparatorTest:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 22002, ~: 21958) -EIP712DomainSeparatorTest:testFuzzHashTypedDataV4(address,address,uint256,uint256,uint64) (runs: 256, μ: 10574, ~: 10574) -EIP712DomainSeparatorTest:testHashTypedDataV4() (gas: 13520) -ERC1155Invariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3437) -ERC1155Test:testBalanceOfBatchCase1() (gas: 281432) -ERC1155Test:testBalanceOfBatchCase2() (gas: 236002) -ERC1155Test:testBalanceOfBatchCase3() (gas: 38322) -ERC1155Test:testBalanceOfBatchLengthsMismatch() (gas: 26717) -ERC1155Test:testBalanceOfBatchZeroAddress() (gas: 17875) -ERC1155Test:testBalanceOfCase1() (gas: 146779) -ERC1155Test:testBalanceOfCase2() (gas: 22617) -ERC1155Test:testBalanceOfZeroAddress() (gas: 11061) -ERC1155Test:testBurnAmountExceedsBalance() (gas: 129983) -ERC1155Test:testBurnBatchAmountExceedsBalance() (gas: 197353) -ERC1155Test:testBurnBatchByApprovedOperator() (gas: 251569) -ERC1155Test:testBurnBatchByNotApprovedOperator() (gas: 31835) -ERC1155Test:testBurnBatchFromZeroAddress() (gas: 25983) -ERC1155Test:testBurnBatchLengthsMismatch() (gas: 41694) -ERC1155Test:testBurnBatchNonExistentTokenIds() (gas: 28292) -ERC1155Test:testBurnBatchSuccess() (gas: 216255) -ERC1155Test:testBurnByApprovedOperator() (gas: 199116) -ERC1155Test:testBurnByNotApprovedOperator() (gas: 148390) -ERC1155Test:testBurnFromZeroAddress() (gas: 17362) -ERC1155Test:testBurnNonExistentTokenId() (gas: 21540) -ERC1155Test:testBurnSuccess() (gas: 143274) -ERC1155Test:testExistsAfterBatchBurn() (gas: 132440) -ERC1155Test:testExistsAfterBatchMint() (gas: 144029) -ERC1155Test:testExistsAfterSingleBurn() (gas: 138531) -ERC1155Test:testExistsAfterSingleMint() (gas: 119756) -ERC1155Test:testExistsBeforeMint() (gas: 10504) -ERC1155Test:testFuzzBurnBatchSuccess(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 133511, ~: 133519) -ERC1155Test:testFuzzBurnSuccess(address,address,uint256) (runs: 256, μ: 141241, ~: 141241) -ERC1155Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13977, ~: 13977) -ERC1155Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48746, ~: 48730) -ERC1155Test:testFuzzSafeBatchTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 227425, ~: 227396) -ERC1155Test:testFuzzSafeBatchTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 191814, ~: 191771) -ERC1155Test:testFuzzSafeBatchTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 565611, ~: 565631) -ERC1155Test:testFuzzSafeBatchTransferFromWithData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 566190, ~: 565788) -ERC1155Test:testFuzzSafeMintBatchEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 153701, ~: 153689) -ERC1155Test:testFuzzSafeMintBatchNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 521418, ~: 521418) -ERC1155Test:testFuzzSafeMintBatchNonMinter(address) (runs: 256, μ: 40926, ~: 40926) -ERC1155Test:testFuzzSafeMintBatchWithData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 521784, ~: 522014) -ERC1155Test:testFuzzSafeMintEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 152766, ~: 152741) -ERC1155Test:testFuzzSafeMintNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 521600, ~: 521600) -ERC1155Test:testFuzzSafeMintNonMinter(address) (runs: 256, μ: 33132, ~: 33132) -ERC1155Test:testFuzzSafeMintWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 522877, ~: 522470) -ERC1155Test:testFuzzSafeTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 206443, ~: 206405) -ERC1155Test:testFuzzSafeTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 170919, ~: 170867) -ERC1155Test:testFuzzSafeTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 610063, ~: 610073) -ERC1155Test:testFuzzSafeTransferFromWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 612045, ~: 611335) -ERC1155Test:testFuzzSetApprovalForAllRevoke(address,address) (runs: 256, μ: 31914, ~: 31884) -ERC1155Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 256, μ: 45258, ~: 45258) -ERC1155Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15772, ~: 15699) -ERC1155Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33755, ~: 33755) -ERC1155Test:testFuzzSetUriNonMinter(address) (runs: 256, μ: 14452, ~: 14452) -ERC1155Test:testFuzzTotalSupplyAfterBatchBurn(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 126961, ~: 126968) -ERC1155Test:testFuzzTotalSupplyAfterBatchMint(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 141705, ~: 141651) -ERC1155Test:testFuzzTotalSupplyAfterSingleBurn(address,uint256,bytes) (runs: 256, μ: 138405, ~: 138376) -ERC1155Test:testFuzzTotalSupplyAfterSingleMint(uint256,uint256,bytes) (runs: 256, μ: 94820, ~: 120208) -ERC1155Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14086, ~: 14086) -ERC1155Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75734, ~: 75704) -ERC1155Test:testHasOwner() (gas: 12615) -ERC1155Test:testInitialSetup() (gas: 2812899) -ERC1155Test:testRenounceOwnershipNonOwner() (gas: 10918) -ERC1155Test:testRenounceOwnershipSuccess() (gas: 22915) -ERC1155Test:testSafeBatchTransferFromByApprovedOperator() (gas: 342145) -ERC1155Test:testSafeBatchTransferFromByNotApprovedOperator() (gas: 261056) -ERC1155Test:testSafeBatchTransferFromEOAReceiver() (gas: 298206) -ERC1155Test:testSafeBatchTransferFromInsufficientBalance() (gas: 267873) -ERC1155Test:testSafeBatchTransferFromLengthsMismatch() (gas: 64116) -ERC1155Test:testSafeBatchTransferFromNoData() (gas: 674269) -ERC1155Test:testSafeBatchTransferFromReceiverFunctionNotImplemented() (gas: 280997) -ERC1155Test:testSafeBatchTransferFromReceiverInvalidReturnIdentifier() (gas: 649199) -ERC1155Test:testSafeBatchTransferFromReceiverReverts() (gas: 642559) -ERC1155Test:testSafeBatchTransferFromReceiverRevertsOnlySingle() (gas: 674332) -ERC1155Test:testSafeBatchTransferFromToZeroAddress() (gas: 257753) -ERC1155Test:testSafeBatchTransferFromWithData() (gas: 676038) -ERC1155Test:testSafeMintBatchEOAReceiver() (gas: 249521) -ERC1155Test:testSafeMintBatchLengthsMismatch() (gas: 66500) -ERC1155Test:testSafeMintBatchNoData() (gas: 618728) -ERC1155Test:testSafeMintBatchNonMinter() (gas: 39827) -ERC1155Test:testSafeMintBatchOverflow() (gas: 265262) -ERC1155Test:testSafeMintBatchReceiverFunctionNotImplemented() (gas: 226871) -ERC1155Test:testSafeMintBatchReceiverInvalidReturnIdentifier() (gas: 599182) -ERC1155Test:testSafeMintBatchReceiverReverts() (gas: 592518) -ERC1155Test:testSafeMintBatchReceiverRevertsOnlySingle() (gas: 618705) -ERC1155Test:testSafeMintBatchToZeroAddress() (gas: 40894) -ERC1155Test:testSafeMintBatchWithData() (gas: 619578) -ERC1155Test:testSafeMintEOAReceiver() (gas: 149958) -ERC1155Test:testSafeMintNoData() (gas: 518170) -ERC1155Test:testSafeMintNonMinter() (gas: 32079) -ERC1155Test:testSafeMintOverflow() (gas: 92104) -ERC1155Test:testSafeMintReceiverFunctionNotImplemented() (gas: 136348) -ERC1155Test:testSafeMintReceiverInvalidReturnIdentifier() (gas: 508148) -ERC1155Test:testSafeMintReceiverReverts() (gas: 501907) -ERC1155Test:testSafeMintToZeroAddress() (gas: 33064) -ERC1155Test:testSafeMintWithData() (gas: 519971) -ERC1155Test:testSafeTransferFromByApprovedOperator() (gas: 206902) -ERC1155Test:testSafeTransferFromByNotApprovedOperator() (gas: 150979) -ERC1155Test:testSafeTransferFromEOAReceiver() (gas: 170125) -ERC1155Test:testSafeTransferFromInsufficientBalance() (gas: 89877) -ERC1155Test:testSafeTransferFromNoData() (gas: 607854) -ERC1155Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 206194) -ERC1155Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 578029) -ERC1155Test:testSafeTransferFromReceiverReverts() (gas: 571745) -ERC1155Test:testSafeTransferFromToZeroAddress() (gas: 87485) -ERC1155Test:testSafeTransferFromWithData() (gas: 611283) -ERC1155Test:testSetApprovalForAllRevoke() (gas: 34137) -ERC1155Test:testSetApprovalForAllSuccess() (gas: 47976) -ERC1155Test:testSetApprovalForAllToSelf() (gas: 11116) -ERC1155Test:testSetMinterNonOwner() (gas: 12717) -ERC1155Test:testSetMinterRemoveOwnerAddress() (gas: 13770) -ERC1155Test:testSetMinterSuccess() (gas: 33587) -ERC1155Test:testSetMinterToZeroAddress() (gas: 15768) -ERC1155Test:testSetUri() (gas: 69232) -ERC1155Test:testSetUriEmpty() (gas: 27504) -ERC1155Test:testSetUriNonMinter() (gas: 13456) +Base64Test:testDataLengthMismatch() (gas: 110404) +Base64Test:testDecodeEmptyString() (gas: 102834) +Base64Test:testDecodeSafeUrl() (gas: 402218) +Base64Test:testDecodeSentence() (gas: 613812) +Base64Test:testDecodeSingleCharacter() (gas: 223929) +Base64Test:testDecodeWithDoublePadding() (gas: 300060) +Base64Test:testDecodeWithNoPadding() (gas: 250701) +Base64Test:testDecodeWithSinglePadding() (gas: 261429) +Base64Test:testEncodeEmptyString() (gas: 165920) +Base64Test:testEncodeSafeUrl() (gas: 190759) +Base64Test:testEncodeSentence() (gas: 217819) +Base64Test:testEncodeSingleCharacter() (gas: 173385) +Base64Test:testEncodeWithDoublePadding() (gas: 178950) +Base64Test:testEncodeWithNoPadding() (gas: 177937) +Base64Test:testEncodeWithSinglePadding() (gas: 179053) +BatchDistributorInvariants:statefulFuzzNoEtherBalance() (runs: 256, calls: 3840, reverts: 3821) +BatchDistributorInvariants:statefulFuzzNoTokenBalance() (runs: 256, calls: 3840, reverts: 3821) +BatchDistributorTest:testDistributeEtherMultipleAddressesSuccess() (gas: 135524) +BatchDistributorTest:testDistributeEtherOneAddressSuccess() (gas: 61680) +BatchDistributorTest:testDistributeEtherReentrancy() (gas: 1645541) +BatchDistributorTest:testDistributeEtherRevertWithInsufficientFunds() (gas: 65209) +BatchDistributorTest:testDistributeEtherRevertWithNoFallbackFunctionForMsgSender() (gas: 141065) +BatchDistributorTest:testDistributeEtherRevertWithNoFallbackFunctionForReceipt() (gas: 36593) +BatchDistributorTest:testDistributeEtherSendsBackExcessiveEther() (gas: 170924) +BatchDistributorTest:testDistributeTokenMultipleAddressesSuccess() (gas: 617059) +BatchDistributorTest:testDistributeTokenOneAddressSuccess() (gas: 579064) +BatchDistributorTest:testDistributeTokenRevertWithInsufficientAllowance() (gas: 573601) +BatchDistributorTest:testDistributeTokenRevertWithInsufficientBalance() (gas: 574254) +BatchDistributorTest:testFuzzDistributeEtherMultipleAddressesSuccess(((address,uint256)[]),uint256) (runs: 256, μ: 1868913, ~: 1856177) +BatchDistributorTest:testFuzzDistributeTokenMultipleAddressesSuccess(((address,uint256)[]),address,uint256) (runs: 256, μ: 1293423, ~: 1295655) +Create2AddressTest:testComputeAddress() (gas: 532159) +Create2AddressTest:testComputeAddressSelf() (gas: 540886) +Create2AddressTest:testFuzzComputeAddress(bytes32,address) (runs: 256, μ: 532754, ~: 532754) +Create2AddressTest:testFuzzComputeAddressSelf(bytes32) (runs: 256, μ: 540907, ~: 540907) +CreateAddressTest:testComputeAddressNonce0x00() (gas: 16315) +CreateAddressTest:testComputeAddressNonce0x7f() (gas: 530219) +CreateAddressTest:testComputeAddressNonceUint16() (gas: 530260) +CreateAddressTest:testComputeAddressNonceUint24() (gas: 530355) +CreateAddressTest:testComputeAddressNonceUint32() (gas: 530317) +CreateAddressTest:testComputeAddressNonceUint40() (gas: 530389) +CreateAddressTest:testComputeAddressNonceUint48() (gas: 530417) +CreateAddressTest:testComputeAddressNonceUint56() (gas: 530441) +CreateAddressTest:testComputeAddressNonceUint64() (gas: 530564) +CreateAddressTest:testComputeAddressNonceUint8() (gas: 530300) +CreateAddressTest:testComputeAddressRevertTooHighNonce() (gas: 10408) +CreateAddressTest:testComputeAddressSelfNonce0x7f() (gas: 534508) +CreateAddressTest:testComputeAddressSelfNonceUint16() (gas: 534718) +CreateAddressTest:testComputeAddressSelfNonceUint24() (gas: 534747) +CreateAddressTest:testComputeAddressSelfNonceUint32() (gas: 534843) +CreateAddressTest:testComputeAddressSelfNonceUint40() (gas: 534872) +CreateAddressTest:testComputeAddressSelfNonceUint48() (gas: 534900) +CreateAddressTest:testComputeAddressSelfNonceUint56() (gas: 534925) +CreateAddressTest:testComputeAddressSelfNonceUint64() (gas: 535028) +CreateAddressTest:testComputeAddressSelfNonceUint8() (gas: 534652) +CreateAddressTest:testComputeAddressSelfRevertTooHighNonce() (gas: 8899) +CreateAddressTest:testFuzzComputeAddressNonce0x7f(uint64,address) (runs: 256, μ: 533177, ~: 533249) +CreateAddressTest:testFuzzComputeAddressNonceUint16(uint64,address) (runs: 256, μ: 532584, ~: 532853) +CreateAddressTest:testFuzzComputeAddressNonceUint24(uint64,address) (runs: 256, μ: 532766, ~: 532833) +CreateAddressTest:testFuzzComputeAddressNonceUint32(uint64,address) (runs: 256, μ: 532722, ~: 532840) +CreateAddressTest:testFuzzComputeAddressNonceUint40(uint64,address) (runs: 256, μ: 532846, ~: 532932) +CreateAddressTest:testFuzzComputeAddressNonceUint48(uint64,address) (runs: 256, μ: 532837, ~: 532916) +CreateAddressTest:testFuzzComputeAddressNonceUint56(uint64,address) (runs: 256, μ: 532854, ~: 532941) +CreateAddressTest:testFuzzComputeAddressNonceUint64(uint64,address) (runs: 256, μ: 532939, ~: 533036) +CreateAddressTest:testFuzzComputeAddressNonceUint8(uint64,address) (runs: 256, μ: 532659, ~: 532707) +CreateAddressTest:testFuzzComputeAddressRevertTooHighNonce(uint256,address) (runs: 256, μ: 12839, ~: 13145) +CreateAddressTest:testFuzzComputeAddressSelfNonce0x7f(uint64) (runs: 256, μ: 539424, ~: 539495) +CreateAddressTest:testFuzzComputeAddressSelfNonceUint16(uint64) (runs: 256, μ: 538631, ~: 538928) +CreateAddressTest:testFuzzComputeAddressSelfNonceUint24(uint64) (runs: 256, μ: 538912, ~: 538980) +CreateAddressTest:testFuzzComputeAddressSelfNonceUint32(uint64) (runs: 256, μ: 538968, ~: 539076) +CreateAddressTest:testFuzzComputeAddressSelfNonceUint40(uint64) (runs: 256, μ: 538978, ~: 539060) +CreateAddressTest:testFuzzComputeAddressSelfNonceUint48(uint64) (runs: 256, μ: 539060, ~: 539134) +CreateAddressTest:testFuzzComputeAddressSelfNonceUint56(uint64) (runs: 256, μ: 539150, ~: 539200) +CreateAddressTest:testFuzzComputeAddressSelfNonceUint64(uint64) (runs: 256, μ: 539233, ~: 539321) +CreateAddressTest:testFuzzComputeAddressSelfNonceUint8(uint64) (runs: 256, μ: 538717, ~: 538771) +CreateAddressTest:testFuzzComputeAddressSelfRevertTooHighNonce(uint256) (runs: 256, μ: 12702, ~: 13020) +ECDSATest:testFuzzRecoverWithInvalidSignature(bytes,string) (runs: 256, μ: 15354, ~: 15358) +ECDSATest:testFuzzRecoverWithTooLongSignature(bytes,string) (runs: 256, μ: 13742, ~: 13746) +ECDSATest:testFuzzRecoverWithValidSignature(string,string) (runs: 256, μ: 21687, ~: 21692) +ECDSATest:testFuzzRecoverWithWrongMessage(string,string,bytes32) (runs: 256, μ: 21762, ~: 21757) +ECDSATest:testRecoverWith0x00Value() (gas: 14961) +ECDSATest:testRecoverWithArbitraryMessage() (gas: 20672) +ECDSATest:testRecoverWithCorrectVersion() (gas: 21126) +ECDSATest:testRecoverWithInvalidSignature() (gas: 14694) +ECDSATest:testRecoverWithTooHighSValue() (gas: 15813) +ECDSATest:testRecoverWithTooLongSignature() (gas: 12565) +ECDSATest:testRecoverWithTooShortSignature() (gas: 14154) +ECDSATest:testRecoverWithValidSignature() (gas: 20732) +ECDSATest:testRecoverWithWrongMessage() (gas: 20744) +ECDSATest:testRecoverWithWrongVersion() (gas: 14967) +EIP712DomainSeparatorTest:testCachedDomainSeparatorV4() (gas: 10476) +EIP712DomainSeparatorTest:testDomainSeparatorV4() (gas: 11731) +EIP712DomainSeparatorTest:testEIP712Domain() (gas: 18055) +EIP712DomainSeparatorTest:testFuzzDomainSeparatorV4(uint8) (runs: 256, μ: 11884, ~: 11906) +EIP712DomainSeparatorTest:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 21486, ~: 21524) +EIP712DomainSeparatorTest:testFuzzHashTypedDataV4(address,address,uint256,uint256,uint64) (runs: 256, μ: 10679, ~: 10679) +EIP712DomainSeparatorTest:testHashTypedDataV4() (gas: 13167) +ERC1155Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3480) +ERC1155Test:testBalanceOfBatchCase1() (gas: 254241) +ERC1155Test:testBalanceOfBatchCase2() (gas: 208833) +ERC1155Test:testBalanceOfBatchCase3() (gas: 35505) +ERC1155Test:testBalanceOfBatchLengthsMismatch() (gas: 23677) +ERC1155Test:testBalanceOfCase1() (gas: 133975) +ERC1155Test:testBalanceOfCase2() (gas: 21807) +ERC1155Test:testBurnAmountExceedsBalance() (gas: 113025) +ERC1155Test:testBurnBatchAmountExceedsBalance() (gas: 178272) +ERC1155Test:testBurnBatchByApprovedOperator() (gas: 231893) +ERC1155Test:testBurnBatchByNotApprovedOperator() (gas: 22104) +ERC1155Test:testBurnBatchFromZeroAddress() (gas: 18165) +ERC1155Test:testBurnBatchLengthsMismatch() (gas: 25851) +ERC1155Test:testBurnBatchNonExistentTokenIds() (gas: 20048) +ERC1155Test:testBurnBatchSuccess() (gas: 196980) +ERC1155Test:testBurnByApprovedOperator() (gas: 180817) +ERC1155Test:testBurnByNotApprovedOperator() (gas: 132582) +ERC1155Test:testBurnFromZeroAddress() (gas: 14072) +ERC1155Test:testBurnNonExistentTokenId() (gas: 16940) +ERC1155Test:testBurnSuccess() (gas: 125117) +ERC1155Test:testExistsAfterBatchBurn() (gas: 113342) +ERC1155Test:testExistsAfterBatchMint() (gas: 128375) +ERC1155Test:testExistsAfterSingleBurn() (gas: 120481) +ERC1155Test:testExistsAfterSingleMint() (gas: 107193) +ERC1155Test:testExistsBeforeMint() (gas: 10481) +ERC1155Test:testFuzzBurnBatchSuccess(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 114463, ~: 114454) +ERC1155Test:testFuzzBurnSuccess(address,address,uint256) (runs: 256, μ: 123428, ~: 123448) +ERC1155Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13962, ~: 13962) +ERC1155Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48758, ~: 48744) +ERC1155Test:testFuzzSafeBatchTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 196071, ~: 196043) +ERC1155Test:testFuzzSafeBatchTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 160588, ~: 160583) +ERC1155Test:testFuzzSafeBatchTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 528710, ~: 528710) +ERC1155Test:testFuzzSafeBatchTransferFromWithData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 529110, ~: 529402) +ERC1155Test:testFuzzSafeMintBatchEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 138147, ~: 138159) +ERC1155Test:testFuzzSafeMintBatchNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 500143, ~: 500143) +ERC1155Test:testFuzzSafeMintBatchNonMinter(address) (runs: 256, μ: 26533, ~: 26533) +ERC1155Test:testFuzzSafeMintBatchWithData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 500436, ~: 500594) +ERC1155Test:testFuzzSafeMintEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 140512, ~: 140511) +ERC1155Test:testFuzzSafeMintNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 503486, ~: 503486) +ERC1155Test:testFuzzSafeMintNonMinter(address) (runs: 256, μ: 26162, ~: 26162) +ERC1155Test:testFuzzSafeMintWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 504633, ~: 504280) +ERC1155Test:testFuzzSafeTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 187771, ~: 187729) +ERC1155Test:testFuzzSafeTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 152372, ~: 152356) +ERC1155Test:testFuzzSafeTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 578758, ~: 578758) +ERC1155Test:testFuzzSafeTransferFromWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 580810, ~: 580106) +ERC1155Test:testFuzzSetApprovalForAllRevoke(address,address) (runs: 256, μ: 31973, ~: 31942) +ERC1155Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 256, μ: 45350, ~: 45350) +ERC1155Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15509, ~: 15499) +ERC1155Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33573, ~: 33584) +ERC1155Test:testFuzzSetUriNonMinter(address) (runs: 256, μ: 14425, ~: 14425) +ERC1155Test:testFuzzTotalSupplyAfterBatchBurn(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 108034, ~: 108025) +ERC1155Test:testFuzzTotalSupplyAfterBatchMint(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 126293, ~: 126323) +ERC1155Test:testFuzzTotalSupplyAfterSingleBurn(address,uint256,bytes) (runs: 256, μ: 120506, ~: 120471) +ERC1155Test:testFuzzTotalSupplyAfterSingleMint(uint256,uint256,bytes) (runs: 256, μ: 75847, ~: 48167) +ERC1155Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14071, ~: 14071) +ERC1155Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75750, ~: 75719) +ERC1155Test:testHasOwner() (gas: 12614) +ERC1155Test:testInitialSetup() (gas: 2892435) +ERC1155Test:testRenounceOwnershipNonOwner() (gas: 10903) +ERC1155Test:testRenounceOwnershipSuccess() (gas: 22923) +ERC1155Test:testSafeBatchTransferFromByApprovedOperator() (gas: 309682) +ERC1155Test:testSafeBatchTransferFromByNotApprovedOperator() (gas: 230894) +ERC1155Test:testSafeBatchTransferFromEOAReceiver() (gas: 272480) +ERC1155Test:testSafeBatchTransferFromInsufficientBalance() (gas: 237279) +ERC1155Test:testSafeBatchTransferFromLengthsMismatch() (gas: 34882) +ERC1155Test:testSafeBatchTransferFromNoData() (gas: 636799) +ERC1155Test:testSafeBatchTransferFromReceiverFunctionNotImplemented() (gas: 258045) +ERC1155Test:testSafeBatchTransferFromReceiverInvalidReturnIdentifier() (gas: 612358) +ERC1155Test:testSafeBatchTransferFromReceiverReverts() (gas: 605601) +ERC1155Test:testSafeBatchTransferFromReceiverRevertsOnlySingle() (gas: 636862) +ERC1155Test:testSafeBatchTransferFromToZeroAddress() (gas: 227713) +ERC1155Test:testSafeBatchTransferFromWithData() (gas: 638012) +ERC1155Test:testSafeMintBatchEOAReceiver() (gas: 233667) +ERC1155Test:testSafeMintBatchLengthsMismatch() (gas: 38000) +ERC1155Test:testSafeMintBatchNoData() (gas: 597371) +ERC1155Test:testSafeMintBatchNonMinter() (gas: 25340) +ERC1155Test:testSafeMintBatchOverflow() (gas: 234974) +ERC1155Test:testSafeMintBatchReceiverFunctionNotImplemented() (gas: 213823) +ERC1155Test:testSafeMintBatchReceiverInvalidReturnIdentifier() (gas: 577983) +ERC1155Test:testSafeMintBatchReceiverReverts() (gas: 571202) +ERC1155Test:testSafeMintBatchReceiverRevertsOnlySingle() (gas: 597348) +ERC1155Test:testSafeMintBatchToZeroAddress() (gas: 26456) +ERC1155Test:testSafeMintBatchWithData() (gas: 597931) +ERC1155Test:testSafeMintEOAReceiver() (gas: 137470) +ERC1155Test:testSafeMintNoData() (gas: 500056) +ERC1155Test:testSafeMintNonMinter() (gas: 24927) +ERC1155Test:testSafeMintOverflow() (gas: 81139) +ERC1155Test:testSafeMintReceiverFunctionNotImplemented() (gas: 128928) +ERC1155Test:testSafeMintReceiverInvalidReturnIdentifier() (gas: 489988) +ERC1155Test:testSafeMintReceiverReverts() (gas: 483541) +ERC1155Test:testSafeMintToZeroAddress() (gas: 25998) +ERC1155Test:testSafeMintWithData() (gas: 501289) +ERC1155Test:testSafeTransferFromByApprovedOperator() (gas: 187564) +ERC1155Test:testSafeTransferFromByNotApprovedOperator() (gas: 134823) +ERC1155Test:testSafeTransferFromEOAReceiver() (gas: 151134) +ERC1155Test:testSafeTransferFromInsufficientBalance() (gas: 78646) +ERC1155Test:testSafeTransferFromNoData() (gas: 576357) +ERC1155Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 186201) +ERC1155Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 547318) +ERC1155Test:testSafeTransferFromReceiverReverts() (gas: 540828) +ERC1155Test:testSafeTransferFromToZeroAddress() (gas: 77670) +ERC1155Test:testSafeTransferFromWithData() (gas: 578698) +ERC1155Test:testSetApprovalForAllRevoke() (gas: 33920) +ERC1155Test:testSetApprovalForAllSuccess() (gas: 47704) +ERC1155Test:testSetApprovalForAllToSelf() (gas: 10855) +ERC1155Test:testSetMinterNonOwner() (gas: 12520) +ERC1155Test:testSetMinterRemoveOwnerAddress() (gas: 13666) +ERC1155Test:testSetMinterSuccess() (gas: 33459) +ERC1155Test:testSetMinterToZeroAddress() (gas: 15706) +ERC1155Test:testSetUri() (gas: 67303) +ERC1155Test:testSetUriEmpty() (gas: 25893) +ERC1155Test:testSetUriNonMinter() (gas: 13269) ERC1155Test:testSupportsInterfaceInvalidInterfaceId() (gas: 8402) ERC1155Test:testSupportsInterfaceInvalidInterfaceIdGasCost() (gas: 9280) ERC1155Test:testSupportsInterfaceSuccess() (gas: 10924) ERC1155Test:testSupportsInterfaceSuccessGasCost() (gas: 9387) -ERC1155Test:testTotalSupplyAfterBatchBurn() (gas: 132335) -ERC1155Test:testTotalSupplyAfterBatchMint() (gas: 143898) -ERC1155Test:testTotalSupplyAfterSingleBurn() (gas: 135287) -ERC1155Test:testTotalSupplyAfterSingleMint() (gas: 119654) -ERC1155Test:testTotalSupplyBeforeMint() (gas: 10437) -ERC1155Test:testTransferOwnershipNonOwner() (gas: 12652) -ERC1155Test:testTransferOwnershipSuccess() (gas: 54040) -ERC1155Test:testTransferOwnershipToZeroAddress() (gas: 15672) -ERC1155Test:testUriBaseAndTokenUriNotSet() (gas: 2768631) -ERC1155Test:testUriBaseAndTokenUriSet() (gas: 65804) -ERC1155Test:testUriNoBaseURI() (gas: 2818691) -ERC1155Test:testUriNoTokenUri() (gas: 20502) -ERC20Invariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3392) -ERC20Invariants:invariantTotalSupply() (runs: 256, calls: 3840, reverts: 3392) -ERC20Test:testApproveExceedingBalanceCase1() (gas: 40945) -ERC20Test:testApproveExceedingBalanceCase2() (gas: 47928) -ERC20Test:testApproveFromZeroAddress() (gas: 13220) -ERC20Test:testApproveSuccessCase1() (gas: 43647) -ERC20Test:testApproveSuccessCase2() (gas: 50712) -ERC20Test:testApproveToZeroAddress() (gas: 16512) -ERC20Test:testBalanceOf() (gas: 18666) -ERC20Test:testBurnFromExceedingBalance() (gas: 31174) -ERC20Test:testBurnFromFromZeroAddress() (gas: 15618) -ERC20Test:testBurnFromInsufficientAllowanceCase1() (gas: 41651) -ERC20Test:testBurnFromInsufficientAllowanceCase2() (gas: 41682) -ERC20Test:testBurnFromSuccessCase1() (gas: 40254) -ERC20Test:testBurnFromSuccessCase2() (gas: 65807) -ERC20Test:testBurnFromUnlimitedAllowance() (gas: 50630) -ERC20Test:testBurnFromZeroAddress() (gas: 11324) -ERC20Test:testBurnInvalidAmount() (gas: 14498) -ERC20Test:testBurnSuccessCase1() (gas: 25793) -ERC20Test:testBurnSuccessCase2() (gas: 31358) -ERC20Test:testCachedDomainSeparator() (gas: 10588) -ERC20Test:testDomainSeparator() (gas: 11838) -ERC20Test:testEIP712Domain() (gas: 18802) -ERC20Test:testFuzzApproveSuccess(address,uint256) (runs: 256, μ: 39843, ~: 41165) -ERC20Test:testFuzzBurnFromInsufficientAllowance(address,uint256,uint8) (runs: 256, μ: 207232, ~: 207422) -ERC20Test:testFuzzBurnFromSuccess(address,uint256) (runs: 256, μ: 340565, ~: 341740) -ERC20Test:testFuzzBurnInvalidAmount(address,uint256) (runs: 256, μ: 16454, ~: 16454) -ERC20Test:testFuzzBurnSuccessCase(uint256) (runs: 256, μ: 316134, ~: 315920) -ERC20Test:testFuzzDomainSeparator(uint8) (runs: 256, μ: 12053, ~: 12074) -ERC20Test:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 22257, ~: 22218) -ERC20Test:testFuzzMintNonMinter(string,uint256) (runs: 256, μ: 13152, ~: 13080) -ERC20Test:testFuzzMintSuccess(string,uint256) (runs: 256, μ: 54960, ~: 55933) -ERC20Test:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 45279, ~: 45277) -ERC20Test:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 71037, ~: 71033) -ERC20Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13979, ~: 13979) -ERC20Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48675, ~: 48659) -ERC20Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15777, ~: 15704) -ERC20Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33773, ~: 33772) -ERC20Test:testFuzzTransferFromInsufficientAllowance(address,address,uint256,uint8) (runs: 256, μ: 205638, ~: 205904) -ERC20Test:testFuzzTransferFromSuccess(address,address,uint256) (runs: 256, μ: 233536, ~: 235763) -ERC20Test:testFuzzTransferInvalidAmount(address,address,uint256) (runs: 256, μ: 16849, ~: 16849) -ERC20Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14068, ~: 14068) -ERC20Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75677, ~: 75650) -ERC20Test:testFuzzTransferSuccess(address,uint256) (runs: 256, μ: 205906, ~: 206896) -ERC20Test:testHasOwner() (gas: 12659) -ERC20Test:testInitialSetup() (gas: 1472592) -ERC20Test:testMintNonMinter() (gas: 12639) -ERC20Test:testMintOverflow() (gas: 16962) -ERC20Test:testMintSuccess() (gas: 51983) -ERC20Test:testMintToZeroAddress() (gas: 15617) -ERC20Test:testPermitBadChainId() (gas: 43804) -ERC20Test:testPermitBadNonce() (gas: 40932) -ERC20Test:testPermitExpiredDeadline() (gas: 17385) -ERC20Test:testPermitOtherSignature() (gas: 41873) -ERC20Test:testPermitReplaySignature() (gas: 73748) -ERC20Test:testPermitSuccess() (gas: 70003) -ERC20Test:testRenounceOwnershipNonOwner() (gas: 10856) -ERC20Test:testRenounceOwnershipSuccess() (gas: 22936) -ERC20Test:testSetMinterNonOwner() (gas: 12721) -ERC20Test:testSetMinterRemoveOwnerAddress() (gas: 13709) -ERC20Test:testSetMinterSuccess() (gas: 33516) -ERC20Test:testSetMinterToZeroAddress() (gas: 15706) -ERC20Test:testTotalSupply() (gas: 11555) -ERC20Test:testTransferFromExceedingBalance() (gas: 32556) -ERC20Test:testTransferFromFromZeroAddress() (gas: 17778) -ERC20Test:testTransferFromInsufficientAllowanceCase1() (gas: 43429) -ERC20Test:testTransferFromInsufficientAllowanceCase2() (gas: 43438) -ERC20Test:testTransferFromSuccess() (gas: 61724) -ERC20Test:testTransferFromToZeroAddress() (gas: 32620) -ERC20Test:testTransferFromUnlimitedAllowance() (gas: 72074) -ERC20Test:testTransferFromZeroAddress() (gas: 19689) -ERC20Test:testTransferInvalidAmount() (gas: 15473) -ERC20Test:testTransferOwnershipNonOwner() (gas: 12611) -ERC20Test:testTransferOwnershipSuccess() (gas: 54038) -ERC20Test:testTransferOwnershipToZeroAddress() (gas: 15586) -ERC20Test:testTransferSuccess() (gas: 43245) -ERC20Test:testTransferToZeroAddress() (gas: 16457) -ERC20Test:testTransferZeroTokens() (gas: 25418) -ERC2981Invariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3840) -ERC2981Test:testDeleteDefaultRoyaltyNonOwner() (gas: 10537) -ERC2981Test:testFuzzDeleteDefaultRoyaltyNonOwner(address) (runs: 256, μ: 13271, ~: 13271) -ERC2981Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13972, ~: 13972) -ERC2981Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 25300, ~: 25300) -ERC2981Test:testFuzzResetTokenRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 96614, ~: 97941) -ERC2981Test:testFuzzResetTokenRoyaltyNonOwner(address) (runs: 256, μ: 13246, ~: 13246) -ERC2981Test:testFuzzRoyaltyInfoDefaultRoyalty(address,uint256,uint256,uint96,uint256) (runs: 256, μ: 80184, ~: 81403) -ERC2981Test:testFuzzRoyaltyInfoDeleteDefaultRoyalty(address,uint256,uint256,uint96,uint256) (runs: 256, μ: 65104, ~: 66104) -ERC2981Test:testFuzzRoyaltyInfoSetTokenRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 121828, ~: 122878) -ERC2981Test:testFuzzRoyaltyInfoSetTokenRoyaltyUpdate(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 168056, ~: 169572) -ERC2981Test:testFuzzRoyaltyInfoUpdateDefaultRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 88068, ~: 89091) -ERC2981Test:testFuzzSetDefaultRoyaltyNonOwner(address) (runs: 256, μ: 15525, ~: 15525) -ERC2981Test:testFuzzSetDefaultRoyaltyTooHighFeeNumerator(uint96) (runs: 256, μ: 21346, ~: 21137) -ERC2981Test:testFuzzSetTokenRoyaltyInvalidReceiver(address) (runs: 256, μ: 18626, ~: 18626) -ERC2981Test:testFuzzSetTokenRoyaltyNonOwner(address) (runs: 256, μ: 15565, ~: 15565) -ERC2981Test:testFuzzSetTokenRoyaltyTooHighFeeNumerator(uint96) (runs: 256, μ: 21387, ~: 21178) -ERC2981Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14039, ~: 14039) -ERC2981Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 30279, ~: 30279) +ERC1155Test:testTotalSupplyAfterBatchBurn() (gas: 113311) +ERC1155Test:testTotalSupplyAfterBatchMint() (gas: 128336) +ERC1155Test:testTotalSupplyAfterSingleBurn() (gas: 117284) +ERC1155Test:testTotalSupplyAfterSingleMint() (gas: 107137) +ERC1155Test:testTotalSupplyBeforeMint() (gas: 10460) +ERC1155Test:testTransferOwnershipNonOwner() (gas: 12455) +ERC1155Test:testTransferOwnershipSuccess() (gas: 53866) +ERC1155Test:testTransferOwnershipToZeroAddress() (gas: 15610) +ERC1155Test:testUriBaseAndTokenUriNotSet() (gas: 2851297) +ERC1155Test:testUriBaseAndTokenUriSet() (gas: 64196) +ERC1155Test:testUriNoBaseURI() (gas: 2900701) +ERC1155Test:testUriNoTokenUri() (gas: 18839) +ERC20Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3481) +ERC20Invariants:statefulFuzzTotalSupply() (runs: 256, calls: 3840, reverts: 3481) +ERC20Test:testApproveExceedingBalanceCase1() (gas: 40805) +ERC20Test:testApproveExceedingBalanceCase2() (gas: 47826) +ERC20Test:testApproveFromZeroAddress() (gas: 12969) +ERC20Test:testApproveSuccessCase1() (gas: 43508) +ERC20Test:testApproveSuccessCase2() (gas: 50611) +ERC20Test:testApproveToZeroAddress() (gas: 16440) +ERC20Test:testBalanceOf() (gas: 18496) +ERC20Test:testBurnFromExceedingBalance() (gas: 30963) +ERC20Test:testBurnFromFromZeroAddress() (gas: 15337) +ERC20Test:testBurnFromInsufficientAllowanceCase1() (gas: 41453) +ERC20Test:testBurnFromInsufficientAllowanceCase2() (gas: 41484) +ERC20Test:testBurnFromSuccessCase1() (gas: 40126) +ERC20Test:testBurnFromSuccessCase2() (gas: 65679) +ERC20Test:testBurnFromUnlimitedAllowance() (gas: 50485) +ERC20Test:testBurnFromZeroAddress() (gas: 11251) +ERC20Test:testBurnInvalidAmount() (gas: 14427) +ERC20Test:testBurnSuccessCase1() (gas: 25797) +ERC20Test:testBurnSuccessCase2() (gas: 31362) +ERC20Test:testCachedDomainSeparator() (gas: 10601) +ERC20Test:testDomainSeparator() (gas: 11831) +ERC20Test:testEIP712Domain() (gas: 18230) +ERC20Test:testFuzzApproveSuccess(address,uint256) (runs: 256, μ: 40736, ~: 41203) +ERC20Test:testFuzzBurnFromInsufficientAllowance(address,uint256,uint8) (runs: 256, μ: 206194, ~: 206066) +ERC20Test:testFuzzBurnFromSuccess(address,uint256) (runs: 256, μ: 339464, ~: 339643) +ERC20Test:testFuzzBurnInvalidAmount(address,uint256) (runs: 256, μ: 16382, ~: 16382) +ERC20Test:testFuzzBurnSuccessCase(uint256) (runs: 256, μ: 314350, ~: 314140) +ERC20Test:testFuzzDomainSeparator(uint8) (runs: 256, μ: 12043, ~: 12067) +ERC20Test:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 21772, ~: 21810) +ERC20Test:testFuzzMintNonMinter(string,uint256) (runs: 256, μ: 12914, ~: 12916) +ERC20Test:testFuzzMintSuccess(string,uint256) (runs: 256, μ: 55120, ~: 55531) +ERC20Test:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 44595, ~: 44597) +ERC20Test:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 70588, ~: 70588) +ERC20Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13941, ~: 13941) +ERC20Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48668, ~: 48654) +ERC20Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15518, ~: 15508) +ERC20Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33594, ~: 33604) +ERC20Test:testFuzzTransferFromInsufficientAllowance(address,address,uint256,uint8) (runs: 256, μ: 204518, ~: 204576) +ERC20Test:testFuzzTransferFromSuccess(address,address,uint256) (runs: 256, μ: 233810, ~: 234152) +ERC20Test:testFuzzTransferInvalidAmount(address,address,uint256) (runs: 256, μ: 16762, ~: 16762) +ERC20Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14053, ~: 14053) +ERC20Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75697, ~: 75665) +ERC20Test:testFuzzTransferSuccess(address,uint256) (runs: 256, μ: 205272, ~: 205643) +ERC20Test:testHasOwner() (gas: 12658) +ERC20Test:testInitialSetup() (gas: 1568383) +ERC20Test:testMintNonMinter() (gas: 12464) +ERC20Test:testMintOverflow() (gas: 16790) +ERC20Test:testMintSuccess() (gas: 51814) +ERC20Test:testMintToZeroAddress() (gas: 15602) +ERC20Test:testPermitBadChainId() (gas: 43413) +ERC20Test:testPermitBadNonce() (gas: 40531) +ERC20Test:testPermitExpiredDeadline() (gas: 17057) +ERC20Test:testPermitOtherSignature() (gas: 41495) +ERC20Test:testPermitReplaySignature() (gas: 73323) +ERC20Test:testPermitSuccess() (gas: 69682) +ERC20Test:testRenounceOwnershipNonOwner() (gas: 10818) +ERC20Test:testRenounceOwnershipSuccess() (gas: 22921) +ERC20Test:testSetMinterNonOwner() (gas: 12528) +ERC20Test:testSetMinterRemoveOwnerAddress() (gas: 13605) +ERC20Test:testSetMinterSuccess() (gas: 33392) +ERC20Test:testSetMinterToZeroAddress() (gas: 15644) +ERC20Test:testTotalSupply() (gas: 11561) +ERC20Test:testTransferFromExceedingBalance() (gas: 32215) +ERC20Test:testTransferFromFromZeroAddress() (gas: 17534) +ERC20Test:testTransferFromInsufficientAllowanceCase1() (gas: 43090) +ERC20Test:testTransferFromInsufficientAllowanceCase2() (gas: 43099) +ERC20Test:testTransferFromSuccess() (gas: 61482) +ERC20Test:testTransferFromToZeroAddress() (gas: 32432) +ERC20Test:testTransferFromUnlimitedAllowance() (gas: 71755) +ERC20Test:testTransferFromZeroAddress() (gas: 19441) +ERC20Test:testTransferInvalidAmount() (gas: 15208) +ERC20Test:testTransferOwnershipNonOwner() (gas: 12418) +ERC20Test:testTransferOwnershipSuccess() (gas: 53868) +ERC20Test:testTransferOwnershipToZeroAddress() (gas: 15524) +ERC20Test:testTransferSuccess() (gas: 43059) +ERC20Test:testTransferToZeroAddress() (gas: 16385) +ERC20Test:testTransferZeroTokens() (gas: 25232) +ERC2981Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3840) +ERC2981Test:testDeleteDefaultRoyaltyNonOwner() (gas: 10651) +ERC2981Test:testFuzzDeleteDefaultRoyaltyNonOwner(address) (runs: 256, μ: 13385, ~: 13385) +ERC2981Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13935, ~: 13935) +ERC2981Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 25266, ~: 25266) +ERC2981Test:testFuzzResetTokenRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 97073, ~: 97799) +ERC2981Test:testFuzzResetTokenRoyaltyNonOwner(address) (runs: 256, μ: 13337, ~: 13337) +ERC2981Test:testFuzzRoyaltyInfoDefaultRoyalty(address,uint256,uint256,uint96,uint256) (runs: 256, μ: 80869, ~: 81225) +ERC2981Test:testFuzzRoyaltyInfoDeleteDefaultRoyalty(address,uint256,uint256,uint96,uint256) (runs: 256, μ: 65737, ~: 65973) +ERC2981Test:testFuzzRoyaltyInfoSetTokenRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 121653, ~: 122711) +ERC2981Test:testFuzzRoyaltyInfoSetTokenRoyaltyUpdate(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 167885, ~: 169409) +ERC2981Test:testFuzzRoyaltyInfoUpdateDefaultRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 88355, ~: 88947) +ERC2981Test:testFuzzSetDefaultRoyaltyNonOwner(address) (runs: 256, μ: 15642, ~: 15642) +ERC2981Test:testFuzzSetDefaultRoyaltyTooHighFeeNumerator(uint96) (runs: 256, μ: 21086, ~: 20916) +ERC2981Test:testFuzzSetTokenRoyaltyInvalidReceiver(address) (runs: 256, μ: 18713, ~: 18713) +ERC2981Test:testFuzzSetTokenRoyaltyNonOwner(address) (runs: 256, μ: 15659, ~: 15659) +ERC2981Test:testFuzzSetTokenRoyaltyTooHighFeeNumerator(uint96) (runs: 256, μ: 21104, ~: 20934) +ERC2981Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14002, ~: 14002) +ERC2981Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 30257, ~: 30257) ERC2981Test:testHasOwner() (gas: 12548) -ERC2981Test:testInitialSetup() (gas: 471061) -ERC2981Test:testRenounceOwnershipNonOwner() (gas: 10871) -ERC2981Test:testRenounceOwnershipSuccess() (gas: 18044) -ERC2981Test:testResetTokenRoyalty() (gas: 94644) -ERC2981Test:testResetTokenRoyaltyNonOwner() (gas: 10597) -ERC2981Test:testRoyaltyInfoDefaultRoyalty() (gas: 75063) -ERC2981Test:testRoyaltyInfoDeleteDefaultRoyalty() (gas: 62938) -ERC2981Test:testRoyaltyInfoRoyaltyAmountOverflow() (gas: 67695) -ERC2981Test:testRoyaltyInfoSetTokenRoyalty() (gas: 118350) -ERC2981Test:testRoyaltyInfoSetTokenRoyaltyUpdate() (gas: 165000) -ERC2981Test:testRoyaltyInfoUpdateDefaultRoyalty() (gas: 84104) -ERC2981Test:testSetDefaultRoyaltyInvalidReceiver() (gas: 17949) -ERC2981Test:testSetDefaultRoyaltyNonOwner() (gas: 12878) -ERC2981Test:testSetDefaultRoyaltyTooHighFeeNumerator() (gas: 17466) -ERC2981Test:testSetTokenRoyaltyInvalidReceiver() (gas: 17958) -ERC2981Test:testSetTokenRoyaltyNonOwner() (gas: 12852) -ERC2981Test:testSetTokenRoyaltyTooHighFeeNumerator() (gas: 17529) +ERC2981Test:testInitialSetup() (gas: 498110) +ERC2981Test:testRenounceOwnershipNonOwner() (gas: 10834) +ERC2981Test:testRenounceOwnershipSuccess() (gas: 18021) +ERC2981Test:testResetTokenRoyalty() (gas: 94307) +ERC2981Test:testResetTokenRoyaltyNonOwner() (gas: 10688) +ERC2981Test:testRoyaltyInfoDefaultRoyalty() (gas: 74866) +ERC2981Test:testRoyaltyInfoDeleteDefaultRoyalty() (gas: 62799) +ERC2981Test:testRoyaltyInfoRoyaltyAmountOverflow() (gas: 67498) +ERC2981Test:testRoyaltyInfoSetTokenRoyalty() (gas: 117928) +ERC2981Test:testRoyaltyInfoSetTokenRoyaltyUpdate() (gas: 164582) +ERC2981Test:testRoyaltyInfoUpdateDefaultRoyalty() (gas: 83705) +ERC2981Test:testSetDefaultRoyaltyInvalidReceiver() (gas: 18059) +ERC2981Test:testSetDefaultRoyaltyNonOwner() (gas: 12995) +ERC2981Test:testSetDefaultRoyaltyTooHighFeeNumerator() (gas: 17350) +ERC2981Test:testSetTokenRoyaltyInvalidReceiver() (gas: 18045) +ERC2981Test:testSetTokenRoyaltyNonOwner() (gas: 12946) +ERC2981Test:testSetTokenRoyaltyTooHighFeeNumerator() (gas: 17390) ERC2981Test:testSupportsInterfaceInvalidInterfaceId() (gas: 8354) ERC2981Test:testSupportsInterfaceInvalidInterfaceIdGasCost() (gas: 9241) ERC2981Test:testSupportsInterfaceSuccess() (gas: 9501) ERC2981Test:testSupportsInterfaceSuccessGasCost() (gas: 9207) -ERC2981Test:testTransferOwnershipNonOwner() (gas: 12649) -ERC2981Test:testTransferOwnershipSuccess() (gas: 22442) -ERC2981Test:testTransferOwnershipToZeroAddress() (gas: 15557) -ERC4626VaultInvariants:invariantTotalAssets() (runs: 256, calls: 3840, reverts: 3243) -ERC4626VaultInvariants:invariantTotalSupply() (runs: 256, calls: 3840, reverts: 3243) -ERC4626VaultTest:testCachedDomainSeparator() (gas: 10565) -ERC4626VaultTest:testDepositInsufficientAllowance() (gas: 82814) -ERC4626VaultTest:testDepositWithNoApproval() (gas: 24749) -ERC4626VaultTest:testDepositZero() (gas: 41119) -ERC4626VaultTest:testDomainSeparator() (gas: 11928) -ERC4626VaultTest:testEIP712Domain() (gas: 18807) -ERC4626VaultTest:testEmptyVaultDeposit() (gas: 567812) -ERC4626VaultTest:testEmptyVaultMint() (gas: 568629) -ERC4626VaultTest:testEmptyVaultRedeem() (gas: 203011) -ERC4626VaultTest:testEmptyVaultwithdraw() (gas: 215856) -ERC4626VaultTest:testFail_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 554484, ~: 557800) -ERC4626VaultTest:testFail_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 556377, ~: 560208) -ERC4626VaultTest:testFuzzDomainSeparator(uint8) (runs: 256, μ: 11946, ~: 11966) -ERC4626VaultTest:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 22181, ~: 22144) -ERC4626VaultTest:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 45214, ~: 45212) -ERC4626VaultTest:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 70960, ~: 70956) -ERC4626VaultTest:testInitialSetup() (gas: 5794290) -ERC4626VaultTest:testMintWithNoApproval() (gas: 24778) -ERC4626VaultTest:testMintZero() (gas: 41225) -ERC4626VaultTest:testMultipleMintDepositRedeemWithdraw() (gas: 377635) -ERC4626VaultTest:testPermitBadChainId() (gas: 43863) -ERC4626VaultTest:testPermitBadNonce() (gas: 40918) -ERC4626VaultTest:testPermitExpiredDeadline() (gas: 17373) -ERC4626VaultTest:testPermitOtherSignature() (gas: 41884) -ERC4626VaultTest:testPermitReplaySignature() (gas: 73728) -ERC4626VaultTest:testPermitSuccess() (gas: 70029) -ERC4626VaultTest:testRedeemInsufficientShares() (gas: 131100) -ERC4626VaultTest:testRedeemWithNoShares() (gas: 13375) -ERC4626VaultTest:testSingleDepositWithdraw() (gas: 178130) -ERC4626VaultTest:testSingleMintRedeem() (gas: 176943) -ERC4626VaultTest:testVaultInteractionsForSomeoneElse() (gas: 224464) -ERC4626VaultTest:testWithdrawInsufficientAllowance() (gas: 122557) -ERC4626VaultTest:testWithdrawInsufficientAssets() (gas: 117837) -ERC4626VaultTest:testWithdrawWithNoAssets() (gas: 21336) -ERC4626VaultTest:test_RT_deposit_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 473734, ~: 476310) -ERC4626VaultTest:test_RT_deposit_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 475609, ~: 477967) -ERC4626VaultTest:test_RT_mint_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 474670, ~: 476379) -ERC4626VaultTest:test_RT_mint_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 476685, ~: 478099) -ERC4626VaultTest:test_RT_redeem_deposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 473696, ~: 476573) -ERC4626VaultTest:test_RT_redeem_mint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 473892, ~: 476751) -ERC4626VaultTest:test_RT_withdraw_deposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 475311, ~: 478372) -ERC4626VaultTest:test_RT_withdraw_mint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 476547, ~: 478697) -ERC4626VaultTest:test_asset((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423474, ~: 427818) -ERC4626VaultTest:test_convertToAssets((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 429508, ~: 433008) -ERC4626VaultTest:test_convertToShares((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 429195, ~: 433223) -ERC4626VaultTest:test_deposit((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 470079, ~: 473856) -ERC4626VaultTest:test_maxDeposit((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423487, ~: 427831) -ERC4626VaultTest:test_maxMint((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423512, ~: 427856) -ERC4626VaultTest:test_maxRedeem((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423626, ~: 427970) -ERC4626VaultTest:test_maxWithdraw((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 425183, ~: 429667) -ERC4626VaultTest:test_mint((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 471053, ~: 474204) -ERC4626VaultTest:test_previewDeposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 466234, ~: 468684) -ERC4626VaultTest:test_previewMint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 467777, ~: 469480) -ERC4626VaultTest:test_previewRedeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 468131, ~: 470717) -ERC4626VaultTest:test_previewWithdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 470611, ~: 472447) -ERC4626VaultTest:test_redeem((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 474207, ~: 476824) -ERC4626VaultTest:test_totalAssets((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 424076, ~: 428420) -ERC4626VaultTest:test_withdraw((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 475492, ~: 478353) -ERC721Invariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3469) -ERC721Invariants:invariantTotalSupply() (runs: 256, calls: 3840, reverts: 3469) -ERC721Test:testApproveClearingApprovalWithNoPriorApproval() (gas: 177662) -ERC721Test:testApproveClearingApprovalWithPriorApproval() (gas: 186718) -ERC721Test:testApproveFromApprovedAddress() (gas: 199707) -ERC721Test:testApproveFromNonOwner() (gas: 173500) -ERC721Test:testApproveFromOperatorAddress() (gas: 224617) -ERC721Test:testApproveInvalidTokenId() (gas: 171496) -ERC721Test:testApproveToOwner() (gas: 167882) -ERC721Test:testApproveToZeroAddress() (gas: 186761) -ERC721Test:testApproveWithNoPriorApproval() (gas: 197063) -ERC721Test:testApproveWithPriorApprovalToDifferentAddress() (gas: 206235) -ERC721Test:testApproveWithPriorApprovalToSameAddress() (gas: 204597) -ERC721Test:testBalanceOfCase1() (gas: 329217) -ERC721Test:testBalanceOfCase2() (gas: 12241) -ERC721Test:testBalanceOfZeroAddress() (gas: 11015) -ERC721Test:testBurnSuccess() (gas: 306577) -ERC721Test:testBurnSuccessViaApproveAndSetApprovalForAll() (gas: 372315) -ERC721Test:testCachedDomainSeparator() (gas: 10588) -ERC721Test:testDomainSeparator() (gas: 11839) -ERC721Test:testEIP712Domain() (gas: 18910) -ERC721Test:testFuzzApproveClearingApprovalWithNoPriorApproval(address,address) (runs: 256, μ: 197161, ~: 197161) -ERC721Test:testFuzzApproveClearingApprovalWithPriorApproval(address,address) (runs: 256, μ: 184786, ~: 184796) -ERC721Test:testFuzzApproveFromNonOwner(address) (runs: 256, μ: 172895, ~: 172895) -ERC721Test:testFuzzApproveFromOperatorAddress(address,address,address) (runs: 256, μ: 223320, ~: 223320) -ERC721Test:testFuzzApproveWithNoPriorApproval(address,address) (runs: 256, μ: 197116, ~: 197116) -ERC721Test:testFuzzApproveWithPriorApproval(address,address) (runs: 256, μ: 204608, ~: 204608) -ERC721Test:testFuzzBurnSuccess(address) (runs: 256, μ: 305917, ~: 305902) -ERC721Test:testFuzzDomainSeparator(uint8) (runs: 256, μ: 12031, ~: 12052) -ERC721Test:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 22357, ~: 22321) -ERC721Test:testFuzzGetApprovedApprovedTokenId(address,address) (runs: 256, μ: 194747, ~: 194747) -ERC721Test:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 201667, ~: 201665) -ERC721Test:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 227868, ~: 227864) -ERC721Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13938, ~: 13938) -ERC721Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48668, ~: 48653) -ERC721Test:testFuzzSafeMintNonMinter(address) (runs: 256, μ: 15894, ~: 15894) -ERC721Test:testFuzzSafeMintSuccess(address[]) (runs: 256, μ: 21048799, ~: 20486327) -ERC721Test:testFuzzSafeTransferFromWithData(address,address,address,bytes) (runs: 256, μ: 1458168, ~: 1458817) -ERC721Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 256, μ: 189558, ~: 189558) -ERC721Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15822, ~: 15749) -ERC721Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33791, ~: 33791) -ERC721Test:testFuzzTokenByIndex(address,string[]) (runs: 256, μ: 21239474, ~: 21216719) -ERC721Test:testFuzzTotalSupply(address,string[]) (runs: 256, μ: 21066522, ~: 21042774) -ERC721Test:testFuzzTransferFrom(address,address,address) (runs: 256, μ: 568567, ~: 568549) -ERC721Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14090, ~: 14090) -ERC721Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75648, ~: 75620) -ERC721Test:testGetApprovedApprovedTokenId() (gas: 194649) -ERC721Test:testGetApprovedInvalidTokenId() (gas: 11097) -ERC721Test:testGetApprovedNotApprovedTokenId() (gas: 170887) -ERC721Test:testHasOwner() (gas: 12585) -ERC721Test:testInitialSetup() (gas: 2408982) -ERC721Test:testOwnerOf() (gas: 166528) -ERC721Test:testOwnerOfInvalidTokenId() (gas: 11052) -ERC721Test:testPermitBadChainId() (gas: 200160) -ERC721Test:testPermitBadNonce() (gas: 197330) -ERC721Test:testPermitExpiredDeadline() (gas: 170692) -ERC721Test:testPermitOtherSignature() (gas: 198207) -ERC721Test:testPermitReplaySignature() (gas: 230573) -ERC721Test:testPermitSuccess() (gas: 226900) -ERC721Test:testRenounceOwnershipNonOwner() (gas: 10944) -ERC721Test:testRenounceOwnershipSuccess() (gas: 22864) -ERC721Test:testSafeMintNonMinter() (gas: 13225) -ERC721Test:testSafeMintOverflow() (gas: 15488) -ERC721Test:testSafeMintReceiverContract() (gas: 389374) -ERC721Test:testSafeMintReceiverContractFunctionNotImplemented() (gas: 116165) -ERC721Test:testSafeMintReceiverContractInvalidReturnIdentifier() (gas: 340401) -ERC721Test:testSafeMintReceiverContractRevertsWithMessage() (gas: 337695) -ERC721Test:testSafeMintReceiverContractRevertsWithPanic() (gas: 337938) -ERC721Test:testSafeMintReceiverContractRevertsWithoutMessage() (gas: 337325) -ERC721Test:testSafeMintSuccess() (gas: 526072) -ERC721Test:testSafeMintToZeroAddress() (gas: 38430) -ERC721Test:testSafeMintTokenAlreadyMinted() (gas: 363393) -ERC721Test:testSafeTransferFromNoData() (gas: 1458305) -ERC721Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 181184) -ERC721Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 405451) -ERC721Test:testSafeTransferFromReceiverRevertsWithMessage() (gas: 402725) -ERC721Test:testSafeTransferFromReceiverRevertsWithPanic() (gas: 402991) -ERC721Test:testSafeTransferFromReceiverRevertsWithoutMessage() (gas: 402355) -ERC721Test:testSafeTransferFromWithData() (gas: 1215115) -ERC721Test:testSetApprovalForAllOperatorIsOwner() (gas: 167663) -ERC721Test:testSetApprovalForAllSuccessCase1() (gas: 196246) -ERC721Test:testSetApprovalForAllSuccessCase2() (gas: 189489) -ERC721Test:testSetApprovalForAllSuccessCase3() (gas: 202786) -ERC721Test:testSetMinterNonOwner() (gas: 12700) -ERC721Test:testSetMinterRemoveOwnerAddress() (gas: 13798) -ERC721Test:testSetMinterSuccess() (gas: 33572) -ERC721Test:testSetMinterToZeroAddress() (gas: 15752) +ERC2981Test:testTransferOwnershipNonOwner() (gas: 12383) +ERC2981Test:testTransferOwnershipSuccess() (gas: 22202) +ERC2981Test:testTransferOwnershipToZeroAddress() (gas: 15473) +ERC4626VaultInvariants:statefulFuzzTotalAssets() (runs: 256, calls: 3840, reverts: 3309) +ERC4626VaultInvariants:statefulFuzzTotalSupply() (runs: 256, calls: 3840, reverts: 3309) +ERC4626VaultTest:testCachedDomainSeparator() (gas: 10578) +ERC4626VaultTest:testDepositInsufficientAllowance() (gas: 82497) +ERC4626VaultTest:testDepositWithNoApproval() (gas: 24432) +ERC4626VaultTest:testDepositZero() (gas: 41097) +ERC4626VaultTest:testDomainSeparator() (gas: 11921) +ERC4626VaultTest:testEIP712Domain() (gas: 18322) +ERC4626VaultTest:testEmptyVaultDeposit() (gas: 567363) +ERC4626VaultTest:testEmptyVaultMint() (gas: 568248) +ERC4626VaultTest:testEmptyVaultRedeem() (gas: 202739) +ERC4626VaultTest:testEmptyVaultwithdraw() (gas: 215472) +ERC4626VaultTest:testFail_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 553791, ~: 556459) +ERC4626VaultTest:testFail_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 555551, ~: 558245) +ERC4626VaultTest:testFuzzDomainSeparator(uint8) (runs: 256, μ: 11934, ~: 11959) +ERC4626VaultTest:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 21796, ~: 21835) +ERC4626VaultTest:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 44543, ~: 44545) +ERC4626VaultTest:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 70478, ~: 70478) +ERC4626VaultTest:testInitialSetup() (gas: 5967264) +ERC4626VaultTest:testMintWithNoApproval() (gas: 24478) +ERC4626VaultTest:testMintZero() (gas: 41220) +ERC4626VaultTest:testMultipleMintDepositRedeemWithdraw() (gas: 377061) +ERC4626VaultTest:testPermitBadChainId() (gas: 43449) +ERC4626VaultTest:testPermitBadNonce() (gas: 40517) +ERC4626VaultTest:testPermitExpiredDeadline() (gas: 17022) +ERC4626VaultTest:testPermitOtherSignature() (gas: 41483) +ERC4626VaultTest:testPermitReplaySignature() (gas: 73280) +ERC4626VaultTest:testPermitSuccess() (gas: 69639) +ERC4626VaultTest:testRedeemInsufficientShares() (gas: 131066) +ERC4626VaultTest:testRedeemWithNoShares() (gas: 13348) +ERC4626VaultTest:testSingleDepositWithdraw() (gas: 177950) +ERC4626VaultTest:testSingleMintRedeem() (gas: 176785) +ERC4626VaultTest:testVaultInteractionsForSomeoneElse() (gas: 224177) +ERC4626VaultTest:testWithdrawInsufficientAllowance() (gas: 122387) +ERC4626VaultTest:testWithdrawInsufficientAssets() (gas: 117794) +ERC4626VaultTest:testWithdrawWithNoAssets() (gas: 21289) +ERC4626VaultTest:test_RT_deposit_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 472163, ~: 473364) +ERC4626VaultTest:test_RT_deposit_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 473864, ~: 474592) +ERC4626VaultTest:test_RT_mint_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 472505, ~: 473436) +ERC4626VaultTest:test_RT_mint_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 474216, ~: 474664) +ERC4626VaultTest:test_RT_redeem_deposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 472539, ~: 473397) +ERC4626VaultTest:test_RT_redeem_mint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 472631, ~: 473483) +ERC4626VaultTest:test_RT_withdraw_deposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 473877, ~: 474620) +ERC4626VaultTest:test_RT_withdraw_mint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 474259, ~: 474730) +ERC4626VaultTest:test_asset((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423387, ~: 426474) +ERC4626VaultTest:test_convertToAssets((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 429095, ~: 430702) +ERC4626VaultTest:test_convertToShares((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 429222, ~: 430723) +ERC4626VaultTest:test_deposit((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 469298, ~: 471292) +ERC4626VaultTest:test_maxDeposit((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423382, ~: 426468) +ERC4626VaultTest:test_maxMint((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423407, ~: 426493) +ERC4626VaultTest:test_maxRedeem((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423522, ~: 426608) +ERC4626VaultTest:test_maxWithdraw((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 424954, ~: 427842) +ERC4626VaultTest:test_mint((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 469412, ~: 471415) +ERC4626VaultTest:test_previewDeposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 464892, ~: 465969) +ERC4626VaultTest:test_previewMint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 465356, ~: 466148) +ERC4626VaultTest:test_previewRedeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 465507, ~: 467401) +ERC4626VaultTest:test_previewWithdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 468153, ~: 468715) +ERC4626VaultTest:test_redeem((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 473101, ~: 474023) +ERC4626VaultTest:test_totalAssets((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423971, ~: 427057) +ERC4626VaultTest:test_withdraw((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 474748, ~: 475212) +ERC721Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3449) +ERC721Invariants:statefulFuzzTotalSupply() (runs: 256, calls: 3840, reverts: 3449) +ERC721Test:testApproveClearingApprovalWithNoPriorApproval() (gas: 177128) +ERC721Test:testApproveClearingApprovalWithPriorApproval() (gas: 186030) +ERC721Test:testApproveFromApprovedAddress() (gas: 198746) +ERC721Test:testApproveFromNonOwner() (gas: 172527) +ERC721Test:testApproveFromOperatorAddress() (gas: 223712) +ERC721Test:testApproveInvalidTokenId() (gas: 170745) +ERC721Test:testApproveToOwner() (gas: 167264) +ERC721Test:testApproveToZeroAddress() (gas: 186073) +ERC721Test:testApproveWithNoPriorApproval() (gas: 196351) +ERC721Test:testApproveWithPriorApprovalToDifferentAddress() (gas: 205369) +ERC721Test:testApproveWithPriorApprovalToSameAddress() (gas: 203909) +ERC721Test:testBalanceOfCase1() (gas: 328294) +ERC721Test:testBalanceOfCase2() (gas: 12078) +ERC721Test:testBalanceOfZeroAddress() (gas: 10942) +ERC721Test:testBurnSuccess() (gas: 305901) +ERC721Test:testBurnSuccessViaApproveAndSetApprovalForAll() (gas: 371439) +ERC721Test:testCachedDomainSeparator() (gas: 10624) +ERC721Test:testDomainSeparator() (gas: 11855) +ERC721Test:testEIP712Domain() (gas: 18341) +ERC721Test:testFuzzApproveClearingApprovalWithNoPriorApproval(address,address) (runs: 256, μ: 196795, ~: 196805) +ERC721Test:testFuzzApproveClearingApprovalWithPriorApproval(address,address) (runs: 256, μ: 184454, ~: 184464) +ERC721Test:testFuzzApproveFromNonOwner(address) (runs: 256, μ: 172100, ~: 172100) +ERC721Test:testFuzzApproveFromOperatorAddress(address,address,address) (runs: 256, μ: 222949, ~: 222949) +ERC721Test:testFuzzApproveWithNoPriorApproval(address,address) (runs: 256, μ: 196750, ~: 196760) +ERC721Test:testFuzzApproveWithPriorApproval(address,address) (runs: 256, μ: 204266, ~: 204276) +ERC721Test:testFuzzBurnSuccess(address) (runs: 256, μ: 305382, ~: 305368) +ERC721Test:testFuzzDomainSeparator(uint8) (runs: 256, μ: 12044, ~: 12068) +ERC721Test:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 21880, ~: 21920) +ERC721Test:testFuzzGetApprovedApprovedTokenId(address,address) (runs: 256, μ: 194381, ~: 194391) +ERC721Test:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 200623, ~: 200625) +ERC721Test:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 227071, ~: 227071) +ERC721Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13923, ~: 13923) +ERC721Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48681, ~: 48667) +ERC721Test:testFuzzSafeMintNonMinter(address) (runs: 256, μ: 15709, ~: 15709) +ERC721Test:testFuzzSafeMintSuccess(address[]) (runs: 256, μ: 19956141, ~: 17134155) +ERC721Test:testFuzzSafeTransferFromWithData(address,address,address,bytes) (runs: 256, μ: 1434320, ~: 1434560) +ERC721Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 256, μ: 189202, ~: 189202) +ERC721Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15540, ~: 15530) +ERC721Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33649, ~: 33660) +ERC721Test:testFuzzTokenByIndex(address,string[]) (runs: 256, μ: 21750033, ~: 21681063) +ERC721Test:testFuzzTotalSupply(address,string[]) (runs: 256, μ: 21569937, ~: 21501832) +ERC721Test:testFuzzTransferFrom(address,address,address) (runs: 256, μ: 565010, ~: 564986) +ERC721Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14075, ~: 14075) +ERC721Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75814, ~: 75782) +ERC721Test:testGetApprovedApprovedTokenId() (gas: 193937) +ERC721Test:testGetApprovedInvalidTokenId() (gas: 11082) +ERC721Test:testGetApprovedNotApprovedTokenId() (gas: 170341) +ERC721Test:testHasOwner() (gas: 12584) +ERC721Test:testInitialSetup() (gas: 2513572) +ERC721Test:testOwnerOf() (gas: 165982) +ERC721Test:testOwnerOfInvalidTokenId() (gas: 11037) +ERC721Test:testPermitBadChainId() (gas: 199386) +ERC721Test:testPermitBadNonce() (gas: 196546) +ERC721Test:testPermitExpiredDeadline() (gas: 169961) +ERC721Test:testPermitOtherSignature() (gas: 197469) +ERC721Test:testPermitReplaySignature() (gas: 229762) +ERC721Test:testPermitSuccess() (gas: 226231) +ERC721Test:testRenounceOwnershipNonOwner() (gas: 10929) +ERC721Test:testRenounceOwnershipSuccess() (gas: 22918) +ERC721Test:testSafeMintNonMinter() (gas: 13040) +ERC721Test:testSafeMintOverflow() (gas: 15309) +ERC721Test:testSafeMintReceiverContract() (gas: 386270) +ERC721Test:testSafeMintReceiverContractFunctionNotImplemented() (gas: 118285) +ERC721Test:testSafeMintReceiverContractInvalidReturnIdentifier() (gas: 337327) +ERC721Test:testSafeMintReceiverContractRevertsWithMessage() (gas: 334583) +ERC721Test:testSafeMintReceiverContractRevertsWithPanic() (gas: 334762) +ERC721Test:testSafeMintReceiverContractRevertsWithoutMessage() (gas: 334318) +ERC721Test:testSafeMintSuccess() (gas: 524569) +ERC721Test:testSafeMintToZeroAddress() (gas: 38396) +ERC721Test:testSafeMintTokenAlreadyMinted() (gas: 362421) +ERC721Test:testSafeTransferFromNoData() (gas: 1439005) +ERC721Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 182694) +ERC721Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 401764) +ERC721Test:testSafeTransferFromReceiverRevertsWithMessage() (gas: 399000) +ERC721Test:testSafeTransferFromReceiverRevertsWithPanic() (gas: 399202) +ERC721Test:testSafeTransferFromReceiverRevertsWithoutMessage() (gas: 398735) +ERC721Test:testSafeTransferFromWithData() (gas: 1194624) +ERC721Test:testSetApprovalForAllOperatorIsOwner() (gas: 167061) +ERC721Test:testSetApprovalForAllSuccessCase1() (gas: 195518) +ERC721Test:testSetApprovalForAllSuccessCase2() (gas: 188777) +ERC721Test:testSetApprovalForAllSuccessCase3() (gas: 202066) +ERC721Test:testSetMinterNonOwner() (gas: 12484) +ERC721Test:testSetMinterRemoveOwnerAddress() (gas: 13671) +ERC721Test:testSetMinterSuccess() (gas: 33484) +ERC721Test:testSetMinterToZeroAddress() (gas: 15667) ERC721Test:testSupportsInterfaceInvalidInterfaceId() (gas: 8567) ERC721Test:testSupportsInterfaceInvalidInterfaceIdGasCost() (gas: 9598) ERC721Test:testSupportsInterfaceSuccess() (gas: 14714) ERC721Test:testSupportsInterfaceSuccessGasCost() (gas: 9365) -ERC721Test:testTokenByIndex() (gas: 556598) -ERC721Test:testTokenByIndexOutOfBounds() (gas: 330882) -ERC721Test:testTokenOfOwnerByIndex() (gas: 576314) -ERC721Test:testTokenOfOwnerByIndexReverts() (gas: 547946) -ERC721Test:testTokenURIAfterBurning() (gas: 138977) -ERC721Test:testTokenURIDefault() (gas: 169547) -ERC721Test:testTokenURIInvalidTokenId() (gas: 13172) -ERC721Test:testTokenURINoBaseURI() (gas: 2528033) -ERC721Test:testTokenURINoTokenUri() (gas: 126741) -ERC721Test:testTotalSupply() (gas: 329166) -ERC721Test:testTransferFrom() (gas: 578101) -ERC721Test:testTransferOwnershipNonOwner() (gas: 12612) -ERC721Test:testTransferOwnershipSuccess() (gas: 54052) -ERC721Test:testTransferOwnershipToZeroAddress() (gas: 15608) -MathTest:testCbrtRoundDown() (gas: 49935) -MathTest:testCbrtRoundUp() (gas: 50582) -MathTest:testCeilDiv() (gas: 14326) -MathTest:testFuzzCbrt(uint256,bool) (runs: 256, μ: 22248, ~: 21924) -MathTest:testFuzzCeilDiv(uint256,uint256) (runs: 256, μ: 9672, ~: 9699) -MathTest:testFuzzInt256Average(int256,int256) (runs: 256, μ: 8572, ~: 8572) -MathTest:testFuzzLog10(uint256,bool) (runs: 256, μ: 10134, ~: 10152) -MathTest:testFuzzLog2(uint256,bool) (runs: 256, μ: 9979, ~: 9985) -MathTest:testFuzzLog256(uint256,bool) (runs: 256, μ: 10016, ~: 10018) -MathTest:testFuzzMulDiv(uint256,uint256,uint256) (runs: 256, μ: 14145, ~: 13888) -MathTest:testFuzzMulDivDomain(uint256,uint256,uint256) (runs: 256, μ: 10487, ~: 10570) -MathTest:testFuzzSignum(int256) (runs: 256, μ: 8464, ~: 8456) -MathTest:testFuzzUint256Average(uint256,uint256) (runs: 256, μ: 8635, ~: 8635) -MathTest:testFuzzWadCbrt(uint256) (runs: 256, μ: 22236, ~: 21948) -MathTest:testFuzzWadExp(int256) (runs: 256, μ: 15258, ~: 15363) -MathTest:testFuzzWadLn(int256) (runs: 256, μ: 16752, ~: 16541) -MathTest:testInt256Average() (gas: 18313) -MathTest:testLog10RoundDown() (gas: 24985) -MathTest:testLog10RoundUp() (gas: 26166) -MathTest:testLog256RoundDown() (gas: 20754) -MathTest:testLog256RoundUp() (gas: 20887) -MathTest:testLog2RoundDown() (gas: 23913) -MathTest:testLog2RoundUp() (gas: 24076) -MathTest:testMulDivDivisionByZero() (gas: 11226) -MathTest:testMulDivOverflow() (gas: 11600) -MathTest:testMulDivRoundDownLargeValues() (gas: 17108) -MathTest:testMulDivRoundDownSmallValues() (gas: 11331) -MathTest:testMulDivRoundUpLargeValues() (gas: 17441) -MathTest:testMulDivRoundUpSmallValues() (gas: 11554) -MathTest:testSignum() (gas: 17356) -MathTest:testUint256Average() (gas: 12646) -MathTest:testWadCbrt() (gas: 48122) -MathTest:testWadExp() (gas: 33776) -MathTest:testWadExpOverflow() (gas: 11127) -MathTest:testWadLn() (gas: 30882) -MathTest:testWadLnNegativeValues() (gas: 11130) -MerkleProofVerificationTest:testFuzzMultiProofVerifySingleLeaf(bytes32[],uint256) (runs: 256, μ: 1649977607, ~: 1649974079) -MerkleProofVerificationTest:testFuzzVerify(bytes32[],uint256) (runs: 256, μ: 135976322, ~: 135972870) -MerkleProofVerificationTest:testFuzzVerifyMultiProofMultipleLeaves(bool,bool,bool) (runs: 256, μ: 412475329, ~: 412475324) -MerkleProofVerificationTest:testInvalidMerkleMultiProof() (gas: 412478774) -MerkleProofVerificationTest:testInvalidMerkleProof() (gas: 33970749) -MerkleProofVerificationTest:testInvalidMerkleProofLength() (gas: 33972916) -MerkleProofVerificationTest:testInvalidMultiProof() (gas: 909636471) -MerkleProofVerificationTest:testMaliciousMultiProofVerify() (gas: 303217500) -MerkleProofVerificationTest:testMultiProofEdgeCase1() (gas: 412460908) -MerkleProofVerificationTest:testMultiProofEdgeCase2() (gas: 412461060) -MerkleProofVerificationTest:testMultiProofVerify() (gas: 412482753) -MerkleProofVerificationTest:testVerify() (gas: 67940109) -MulticallTest:testMulticallRevert() (gas: 545382964) -MulticallTest:testMulticallSelfRevert() (gas: 1090186642) -MulticallTest:testMulticallSelfSuccess() (gas: 1635537407) -MulticallTest:testMulticallSuccess() (gas: 545390333) -MulticallTest:testMulticallValueRevertCase1() (gas: 545926302) -MulticallTest:testMulticallValueRevertCase2() (gas: 545933664) -MulticallTest:testMulticallValueSuccess() (gas: 545959264) -MulticallTest:testMultistaticcallRevert() (gas: 8937393460525252382) -MulticallTest:testMultistaticcallSuccess() (gas: 545354391) -Ownable2StepInvariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3840) -Ownable2StepInvariants:invariantPendingOwner() (runs: 256, calls: 3840, reverts: 3840) -Ownable2StepTest:testAcceptOwnershipNonPendingOwner() (gas: 47654) -Ownable2StepTest:testAcceptOwnershipSuccess() (gas: 40806) -Ownable2StepTest:testFuzzAcceptOwnershipNonPendingOwner(address) (runs: 256, μ: 46864, ~: 46864) -Ownable2StepTest:testFuzzAcceptOwnershipSuccess(address,address) (runs: 256, μ: 67636, ~: 67608) -Ownable2StepTest:testFuzzPendingOwnerResetAfterRenounceOwnership(address) (runs: 256, μ: 40152, ~: 40135) -Ownable2StepTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13954, ~: 13954) -Ownable2StepTest:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 45365, ~: 45348) -Ownable2StepTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14106, ~: 14106) -Ownable2StepTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 52203, ~: 52203) +ERC721Test:testTokenByIndex() (gas: 555077) +ERC721Test:testTokenByIndexOutOfBounds() (gas: 329871) +ERC721Test:testTokenOfOwnerByIndex() (gas: 574732) +ERC721Test:testTokenOfOwnerByIndexReverts() (gas: 545756) +ERC721Test:testTokenURIAfterBurning() (gas: 138556) +ERC721Test:testTokenURIDefault() (gas: 168128) +ERC721Test:testTokenURIInvalidTokenId() (gas: 13142) +ERC721Test:testTokenURINoBaseURI() (gas: 2632989) +ERC721Test:testTokenURINoTokenUri() (gas: 125697) +ERC721Test:testTotalSupply() (gas: 328205) +ERC721Test:testTransferFrom() (gas: 574253) +ERC721Test:testTransferOwnershipNonOwner() (gas: 12419) +ERC721Test:testTransferOwnershipSuccess() (gas: 53974) +ERC721Test:testTransferOwnershipToZeroAddress() (gas: 15546) +MathTest:testCbrtRoundDown() (gas: 51656) +MathTest:testCbrtRoundUp() (gas: 52303) +MathTest:testCeilDiv() (gas: 14712) +MathTest:testFuzzCbrt(uint256,bool) (runs: 256, μ: 22309, ~: 22212) +MathTest:testFuzzCeilDiv(uint256,uint256) (runs: 256, μ: 9765, ~: 9770) +MathTest:testFuzzInt256Average(int256,int256) (runs: 256, μ: 8625, ~: 8625) +MathTest:testFuzzLog10(uint256,bool) (runs: 256, μ: 10351, ~: 10311) +MathTest:testFuzzLog2(uint256,bool) (runs: 256, μ: 10061, ~: 10025) +MathTest:testFuzzLog256(uint256,bool) (runs: 256, μ: 10193, ~: 10119) +MathTest:testFuzzMulDiv(uint256,uint256,uint256) (runs: 256, μ: 14325, ~: 14078) +MathTest:testFuzzMulDivDomain(uint256,uint256,uint256) (runs: 256, μ: 10856, ~: 10890) +MathTest:testFuzzSignum(int256) (runs: 256, μ: 8507, ~: 8500) +MathTest:testFuzzUint256Average(uint256,uint256) (runs: 256, μ: 8688, ~: 8688) +MathTest:testFuzzWadCbrt(uint256) (runs: 256, μ: 22265, ~: 22077) +MathTest:testFuzzWadExp(int256) (runs: 256, μ: 14770, ~: 15077) +MathTest:testFuzzWadLn(int256) (runs: 256, μ: 16362, ~: 16125) +MathTest:testInt256Average() (gas: 18843) +MathTest:testLog10RoundDown() (gas: 26211) +MathTest:testLog10RoundUp() (gas: 27392) +MathTest:testLog256RoundDown() (gas: 21459) +MathTest:testLog256RoundUp() (gas: 21592) +MathTest:testLog2RoundDown() (gas: 23966) +MathTest:testLog2RoundUp() (gas: 24129) +MathTest:testMulDivDivisionByZero() (gas: 11346) +MathTest:testMulDivOverflow() (gas: 11702) +MathTest:testMulDivRoundDownLargeValues() (gas: 17568) +MathTest:testMulDivRoundDownSmallValues() (gas: 11619) +MathTest:testMulDivRoundUpLargeValues() (gas: 17901) +MathTest:testMulDivRoundUpSmallValues() (gas: 11836) +MathTest:testSignum() (gas: 17752) +MathTest:testUint256Average() (gas: 12911) +MathTest:testWadCbrt() (gas: 48690) +MathTest:testWadExp() (gas: 34590) +MathTest:testWadExpOverflow() (gas: 11169) +MathTest:testWadLn() (gas: 31356) +MathTest:testWadLnNegativeValues() (gas: 11096) +MerkleProofVerificationTest:testFuzzMultiProofVerifySingleLeaf(bytes32[],uint256) (runs: 256, μ: 261873, ~: 262371) +MerkleProofVerificationTest:testFuzzVerify(bytes32[],uint256) (runs: 256, μ: 176339, ~: 176071) +MerkleProofVerificationTest:testFuzzVerifyMultiProofMultipleLeaves(bool,bool,bool) (runs: 256, μ: 45520, ~: 45511) +MerkleProofVerificationTest:testInvalidMerkleMultiProof() (gas: 46709) +MerkleProofVerificationTest:testInvalidMerkleProof() (gas: 18776) +MerkleProofVerificationTest:testInvalidMerkleProofLength() (gas: 20630) +MerkleProofVerificationTest:testInvalidMultiProof() (gas: 86957) +MerkleProofVerificationTest:testMaliciousMultiProofVerify() (gas: 36089) +MerkleProofVerificationTest:testMultiProofEdgeCase1() (gas: 31077) +MerkleProofVerificationTest:testMultiProofEdgeCase2() (gas: 31229) +MerkleProofVerificationTest:testMultiProofVerify() (gas: 50368) +MerkleProofVerificationTest:testVerify() (gas: 35450) +MessageHashUtilsTest:testEthSignedMessageHash() (gas: 8614) +MessageHashUtilsTest:testFuzzEthSignedMessageHash(string) (runs: 256, μ: 9321, ~: 9315) +MessageHashUtilsTest:testFuzzToDataWithIntendedValidatorHash(address,bytes) (runs: 256, μ: 9906, ~: 9890) +MessageHashUtilsTest:testFuzzToDataWithIntendedValidatorHashSelf(bytes) (runs: 256, μ: 11891, ~: 11877) +MessageHashUtilsTest:testFuzzToTypedDataHash(string,string) (runs: 256, μ: 9940, ~: 9941) +MessageHashUtilsTest:testToDataWithIntendedValidatorHash() (gas: 11134) +MessageHashUtilsTest:testToDataWithIntendedValidatorHashSelf() (gas: 11752) +MessageHashUtilsTest:testToTypedDataHash() (gas: 8736) +MulticallTest:testMulticallRevert() (gas: 1150294) +MulticallTest:testMulticallSelfRevert() (gas: 2212936) +MulticallTest:testMulticallSelfSuccess() (gas: 3334102) +MulticallTest:testMulticallSuccess() (gas: 1158761) +MulticallTest:testMulticallValueRevertCase1() (gas: 1209186) +MulticallTest:testMulticallValueRevertCase2() (gas: 1210120) +MulticallTest:testMulticallValueSuccess() (gas: 1237224) +MulticallTest:testMultistaticcallRevert() (gas: 8937393460516748812) +MulticallTest:testMultistaticcallSuccess() (gas: 1127930) +Ownable2StepInvariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3840) +Ownable2StepInvariants:statefulFuzzPendingOwner() (runs: 256, calls: 3840, reverts: 3840) +Ownable2StepTest:testAcceptOwnershipNonPendingOwner() (gas: 47364) +Ownable2StepTest:testAcceptOwnershipSuccess() (gas: 40661) +Ownable2StepTest:testFuzzAcceptOwnershipNonPendingOwner(address) (runs: 256, μ: 46803, ~: 46803) +Ownable2StepTest:testFuzzAcceptOwnershipSuccess(address,address) (runs: 256, μ: 67719, ~: 67688) +Ownable2StepTest:testFuzzPendingOwnerResetAfterRenounceOwnership(address) (runs: 256, μ: 40131, ~: 40117) +Ownable2StepTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13872, ~: 13872) +Ownable2StepTest:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 45431, ~: 45417) +Ownable2StepTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14024, ~: 14024) +Ownable2StepTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 52221, ~: 52221) Ownable2StepTest:testHasOwner() (gas: 12527) -Ownable2StepTest:testInitialSetup() (gas: 237121) -Ownable2StepTest:testPendingOwnerResetAfterRenounceOwnership() (gas: 41029) -Ownable2StepTest:testRenounceOwnershipNonOwner() (gas: 10941) -Ownable2StepTest:testRenounceOwnershipSuccess() (gas: 20229) -Ownable2StepTest:testTransferOwnershipNonOwner() (gas: 12618) -Ownable2StepTest:testTransferOwnershipSuccess() (gas: 45966) -OwnableInvariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3840) -OwnableTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13927, ~: 13927) -OwnableTest:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 25251, ~: 25251) -OwnableTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14080, ~: 14080) -OwnableTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 30275, ~: 30275) +Ownable2StepTest:testInitialSetup() (gas: 241599) +Ownable2StepTest:testPendingOwnerResetAfterRenounceOwnership() (gas: 40828) +Ownable2StepTest:testRenounceOwnershipNonOwner() (gas: 10859) +Ownable2StepTest:testRenounceOwnershipSuccess() (gas: 20268) +Ownable2StepTest:testTransferOwnershipNonOwner() (gas: 12307) +Ownable2StepTest:testTransferOwnershipSuccess() (gas: 45746) +OwnableInvariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3840) +OwnableTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13913, ~: 13913) +OwnableTest:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 25263, ~: 25263) +OwnableTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14066, ~: 14066) +OwnableTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 30299, ~: 30299) OwnableTest:testHasOwner() (gas: 12524) -OwnableTest:testInitialSetup() (gas: 201574) -OwnableTest:testRenounceOwnershipNonOwner() (gas: 10847) +OwnableTest:testInitialSetup() (gas: 212043) +OwnableTest:testRenounceOwnershipNonOwner() (gas: 10833) OwnableTest:testRenounceOwnershipSuccess() (gas: 17974) -OwnableTest:testTransferOwnershipNonOwner() (gas: 12559) -OwnableTest:testTransferOwnershipSuccess() (gas: 22372) -OwnableTest:testTransferOwnershipToZeroAddress() (gas: 15511) -SignatureCheckerTest:testEIP1271NoIsValidSignatureFunction() (gas: 23596) -SignatureCheckerTest:testEIP1271WithInvalidSignature(bytes,string) (runs: 256, μ: 24150, ~: 24147) -SignatureCheckerTest:testEIP1271WithInvalidSignature1() (gas: 34558) -SignatureCheckerTest:testEIP1271WithInvalidSignature2() (gas: 30166) -SignatureCheckerTest:testEIP1271WithInvalidSigner() (gas: 34636) -SignatureCheckerTest:testEIP1271WithMaliciousWallet() (gas: 24529) -SignatureCheckerTest:testEIP1271WithValidSignature() (gas: 34545) -SignatureCheckerTest:testEOAWithInvalidSignature1() (gas: 21073) -SignatureCheckerTest:testEOAWithInvalidSignature2() (gas: 21381) -SignatureCheckerTest:testEOAWithInvalidSigner() (gas: 21165) -SignatureCheckerTest:testEOAWithTooHighSValue() (gas: 18427) -SignatureCheckerTest:testEOAWithValidSignature() (gas: 20290) -SignatureCheckerTest:testFuzzEIP1271WithInvalidSigner(string,string) (runs: 256, μ: 36548, ~: 36614) -SignatureCheckerTest:testFuzzEIP1271WithValidSignature(string) (runs: 256, μ: 35124, ~: 35118) -SignatureCheckerTest:testFuzzEOAWithInvalidSignature(bytes,string) (runs: 256, μ: 17555, ~: 17554) -SignatureCheckerTest:testFuzzEOAWithInvalidSigner(string,string) (runs: 256, μ: 22184, ~: 22245) -SignatureCheckerTest:testFuzzEOAWithValidSignature(string,string) (runs: 256, μ: 21303, ~: 21364) +OwnableTest:testTransferOwnershipNonOwner() (gas: 12316) +OwnableTest:testTransferOwnershipSuccess() (gas: 22155) +OwnableTest:testTransferOwnershipToZeroAddress() (gas: 15450) +P256Test:testFuzzVerifyWithValidSignature(string,string) (runs: 256, μ: 973776, ~: 733509) +P256Test:testVerifyWithFlippedValues() (gas: 1106912) +P256Test:testVerifyWithInvalidSignature() (gas: 552113) +P256Test:testVerifyWithOutOfBoundsPublicKey() (gas: 16907) +P256Test:testVerifyWithTooHighSValue() (gas: 9293) +P256Test:testVerifyWithValidSignature() (gas: 554107) +P256Test:testVerifyWithZeroInputs() (gas: 8654) +P256Test:testVerifyWycheproofData() (gas: 230702862) +SignatureCheckerTest:testEIP1271NoIsValidSignatureFunction() (gas: 18775) +SignatureCheckerTest:testEIP1271WithInvalidSignature(bytes,string) (runs: 256, μ: 23555, ~: 23550) +SignatureCheckerTest:testEIP1271WithInvalidSignature1() (gas: 29701) +SignatureCheckerTest:testEIP1271WithInvalidSignature2() (gas: 31390) +SignatureCheckerTest:testEIP1271WithInvalidSigner() (gas: 29779) +SignatureCheckerTest:testEIP1271WithMaliciousWallet() (gas: 19672) +SignatureCheckerTest:testEIP1271WithValidSignature() (gas: 29688) +SignatureCheckerTest:testEOAWithInvalidSignature1() (gas: 19374) +SignatureCheckerTest:testEOAWithInvalidSignature2() (gas: 22969) +SignatureCheckerTest:testEOAWithInvalidSigner() (gas: 19466) +SignatureCheckerTest:testEOAWithTooHighSValue() (gas: 19984) +SignatureCheckerTest:testEOAWithValidSignature() (gas: 19382) +SignatureCheckerTest:testFuzzEIP1271WithInvalidSigner(string,string) (runs: 256, μ: 31612, ~: 31621) +SignatureCheckerTest:testFuzzEIP1271WithValidSignature(string) (runs: 256, μ: 30267, ~: 30261) +SignatureCheckerTest:testFuzzEOAWithInvalidSignature(bytes,string) (runs: 256, μ: 16385, ~: 16385) +SignatureCheckerTest:testFuzzEOAWithInvalidSigner(string,string) (runs: 256, μ: 20406, ~: 20410) +SignatureCheckerTest:testFuzzEOAWithValidSignature(string,string) (runs: 256, μ: 20316, ~: 20320) SignatureCheckerTest:testInitialSetup() (gas: 8292) -TimelockControllerInvariants:invariantExecutedLessThanOrEqualToScheduled() (runs: 256, calls: 3840, reverts: 1282) -TimelockControllerInvariants:invariantExecutedProposalCancellation() (runs: 256, calls: 3840, reverts: 1336) -TimelockControllerInvariants:invariantExecutingCancelledProposal() (runs: 256, calls: 3840, reverts: 1358) -TimelockControllerInvariants:invariantExecutingNotReadyProposal() (runs: 256, calls: 3840, reverts: 1272) -TimelockControllerInvariants:invariantOnceProposalExecution() (runs: 256, calls: 3840, reverts: 1336) -TimelockControllerInvariants:invariantProposalsExecutedMatchCount() (runs: 256, calls: 3840, reverts: 1282) -TimelockControllerInvariants:invariantSumOfProposals() (runs: 256, calls: 3840, reverts: 1282) -TimelockControllerTest:testAdminCannotBatchExecute() (gas: 750573) -TimelockControllerTest:testAdminCannotBatchSchedule() (gas: 748359) -TimelockControllerTest:testAdminCannotCancel() (gas: 13280) -TimelockControllerTest:testAdminCannotExecute() (gas: 18372) -TimelockControllerTest:testAdminCannotSchedule() (gas: 16044) -TimelockControllerTest:testBatchCancelFinished() (gas: 4641389) -TimelockControllerTest:testBatchEqualAndGreaterMinimumDelay() (gas: 6145268) -TimelockControllerTest:testBatchHasBeenExecuted() (gas: 4639611) -TimelockControllerTest:testBatchHasNotBeenExecuted() (gas: 3078883) -TimelockControllerTest:testBatchInsufficientDelay() (gas: 1532719) -TimelockControllerTest:testBatchMinimumDelayUpdate() (gas: 3086552) -TimelockControllerTest:testBatchOperationAlreadyScheduled() (gas: 4593355) -TimelockControllerTest:testBatchOperationIsNotReady() (gas: 4598672) -TimelockControllerTest:testBatchPendingIfExecuted() (gas: 4638226) -TimelockControllerTest:testBatchPendingIfNotYetExecuted() (gas: 3078891) -TimelockControllerTest:testBatchPredecessorInvalid() (gas: 4601024) -TimelockControllerTest:testBatchPredecessorMultipleNotExecuted() (gas: 6141708) -TimelockControllerTest:testBatchPredecessorNotExecuted() (gas: 7662979) -TimelockControllerTest:testBatchPredecessorNotScheduled() (gas: 6116884) -TimelockControllerTest:testBatchReadyAfterTheExecutionTime() (gas: 3079456) -TimelockControllerTest:testBatchReadyBeforeTheExecutionTime() (gas: 3079473) -TimelockControllerTest:testBatchReadyOnTheExecutionTime() (gas: 3079359) -TimelockControllerTest:testBatchScheduleAndExecuteWithEmptySalt() (gas: 4647401) -TimelockControllerTest:testBatchScheduleAndExecuteWithNonEmptySalt() (gas: 4650846) -TimelockControllerTest:testBatchTargetRevert() (gas: 9186333) -TimelockControllerTest:testBatchTimestampHasBeenExecuted() (gas: 4638064) -TimelockControllerTest:testBatchTimestampHasNotBeenExecuted() (gas: 3078711) +TimelockControllerInvariants:statefulFuzzExecutedLessThanOrEqualToScheduled() (runs: 256, calls: 3840, reverts: 1288) +TimelockControllerInvariants:statefulFuzzExecutedProposalCancellation() (runs: 256, calls: 3840, reverts: 1258) +TimelockControllerInvariants:statefulFuzzExecutingCancelledProposal() (runs: 256, calls: 3840, reverts: 1275) +TimelockControllerInvariants:statefulFuzzExecutingNotReadyProposal() (runs: 256, calls: 3840, reverts: 1275) +TimelockControllerInvariants:statefulFuzzOnceProposalExecution() (runs: 256, calls: 3840, reverts: 1250) +TimelockControllerInvariants:statefulFuzzProposalsExecutedMatchCount() (runs: 256, calls: 3840, reverts: 1269) +TimelockControllerInvariants:statefulFuzzSumOfProposals() (runs: 256, calls: 3840, reverts: 1271) +TimelockControllerTest:testAdminCannotBatchExecute() (gas: 750660) +TimelockControllerTest:testAdminCannotBatchSchedule() (gas: 748447) +TimelockControllerTest:testAdminCannotCancel() (gas: 13375) +TimelockControllerTest:testAdminCannotExecute() (gas: 18449) +TimelockControllerTest:testAdminCannotSchedule() (gas: 16122) +TimelockControllerTest:testBatchCancelFinished() (gas: 4638366) +TimelockControllerTest:testBatchEqualAndGreaterMinimumDelay() (gas: 6141734) +TimelockControllerTest:testBatchHasBeenExecuted() (gas: 4636479) +TimelockControllerTest:testBatchHasNotBeenExecuted() (gas: 3077116) +TimelockControllerTest:testBatchInsufficientDelay() (gas: 1532099) +TimelockControllerTest:testBatchMinimumDelayUpdate() (gas: 3084819) +TimelockControllerTest:testBatchOperationAlreadyScheduled() (gas: 4590967) +TimelockControllerTest:testBatchOperationIsNotReady() (gas: 4596283) +TimelockControllerTest:testBatchPendingIfExecuted() (gas: 4635093) +TimelockControllerTest:testBatchPendingIfNotYetExecuted() (gas: 3077124) +TimelockControllerTest:testBatchPredecessorInvalid() (gas: 4598616) +TimelockControllerTest:testBatchPredecessorMultipleNotExecuted() (gas: 6138775) +TimelockControllerTest:testBatchPredecessorNotExecuted() (gas: 7658783) +TimelockControllerTest:testBatchPredecessorNotScheduled() (gas: 6113752) +TimelockControllerTest:testBatchReadyAfterTheExecutionTime() (gas: 3077669) +TimelockControllerTest:testBatchReadyBeforeTheExecutionTime() (gas: 3077706) +TimelockControllerTest:testBatchReadyOnTheExecutionTime() (gas: 3077572) +TimelockControllerTest:testBatchScheduleAndExecuteWithEmptySalt() (gas: 4644296) +TimelockControllerTest:testBatchScheduleAndExecuteWithNonEmptySalt() (gas: 4647741) +TimelockControllerTest:testBatchTargetRevert() (gas: 9182256) +TimelockControllerTest:testBatchTimestampHasBeenExecuted() (gas: 4634931) +TimelockControllerTest:testBatchTimestampHasNotBeenExecuted() (gas: 3076931) TimelockControllerTest:testCanReceiveEther() (gas: 15016) -TimelockControllerTest:testCancellerCanCancelOperation() (gas: 3065173) -TimelockControllerTest:testCompleteOperationWithAssignExecutorRoleToZeroAddress() (gas: 125411) -TimelockControllerTest:testCompletePipelineOperationMinimumDelayUpdate() (gas: 73758) -TimelockControllerTest:testCompletePipelineOperationSetRoleAdmin() (gas: 101204) -TimelockControllerTest:testExecutorCanBatchExecute() (gas: 3049249) -TimelockControllerTest:testExecutorCanExecute() (gas: 29870) -TimelockControllerTest:testExecutorCannotBatchSchedule() (gas: 1485375) -TimelockControllerTest:testExecutorCannotCancel() (gas: 15281) -TimelockControllerTest:testExecutorCannotSchedule() (gas: 19023) -TimelockControllerTest:testFuzzBatchValue(uint256) (runs: 256, μ: 4653431, ~: 4653583) -TimelockControllerTest:testFuzzHashOperation(address,uint256,bytes,bytes32,bytes32) (runs: 256, μ: 11107, ~: 10990) -TimelockControllerTest:testFuzzHashOperationBatch(address[],uint256[],bytes[],bytes32,bytes32) (runs: 256, μ: 1880733, ~: 1890407) -TimelockControllerTest:testFuzzOperationValue(uint256) (runs: 256, μ: 113852, ~: 114011) -TimelockControllerTest:testHandleERC1155() (gas: 41507913) -TimelockControllerTest:testHandleERC721() (gas: 7058093) -TimelockControllerTest:testHashOperation() (gas: 13112) -TimelockControllerTest:testHashOperationBatch() (gas: 1526310) -TimelockControllerTest:testInitialSetup() (gas: 4274954) -TimelockControllerTest:testInvalidOperation() (gas: 10718) -TimelockControllerTest:testOperationAlreadyScheduled() (gas: 52329) -TimelockControllerTest:testOperationCancelFinished() (gas: 101902) -TimelockControllerTest:testOperationEqualAndGreaterMinimumDelay() (gas: 90758) -TimelockControllerTest:testOperationHasBeenExecuted() (gas: 100157) -TimelockControllerTest:testOperationHasNotBeenExecuted() (gas: 52730) -TimelockControllerTest:testOperationInsufficientDelay() (gas: 19456) -TimelockControllerTest:testOperationMinimumDelayUpdate() (gas: 61739) -TimelockControllerTest:testOperationOperationIsNotReady() (gas: 57684) -TimelockControllerTest:testOperationPendingIfExecuted() (gas: 98728) -TimelockControllerTest:testOperationPendingIfNotYetExecuted() (gas: 52794) -TimelockControllerTest:testOperationPredecessorInvalid() (gas: 62863) -TimelockControllerTest:testOperationPredecessorMultipleNotExecuted() (gas: 92521) -TimelockControllerTest:testOperationPredecessorNotExecuted() (gas: 99305) -TimelockControllerTest:testOperationPredecessorNotScheduled() (gas: 66765) -TimelockControllerTest:testOperationReadyAfterTheExecutionTime() (gas: 53349) -TimelockControllerTest:testOperationReadyBeforeTheExecutionTime() (gas: 53292) -TimelockControllerTest:testOperationReadyOnTheExecutionTime() (gas: 53186) -TimelockControllerTest:testOperationTargetRevert() (gas: 110186) -TimelockControllerTest:testOperationTimestampHasBeenExecuted() (gas: 98502) -TimelockControllerTest:testOperationTimestampHasNotBeenExecuted() (gas: 52581) -TimelockControllerTest:testProposerCanBatchSchedule() (gas: 3088645) -TimelockControllerTest:testProposerCanCancel() (gas: 20179) -TimelockControllerTest:testProposerCanSchedule() (gas: 75609) -TimelockControllerTest:testProposerCannotBatchExecute() (gas: 1489786) -TimelockControllerTest:testProposerCannotExecute() (gas: 23549) -TimelockControllerTest:testReturnsLaterMinimumDelayForCalls() (gas: 20711) -TimelockControllerTest:testRevertWhenNotTimelock() (gas: 9053) -TimelockControllerTest:testScheduleAndExecuteWithEmptySalt() (gas: 107956) -TimelockControllerTest:testScheduleAndExecuteWithNonEmptySalt() (gas: 111313) -TimelockControllerTest:testStrangerCannotBatchExecute() (gas: 748592) -TimelockControllerTest:testStrangerCannotBatchSchedule() (gas: 746399) -TimelockControllerTest:testStrangerCannotCancel() (gas: 11276) -TimelockControllerTest:testStrangerCannotExecute() (gas: 16389) -TimelockControllerTest:testStrangerCannotSchedule() (gas: 14173) +TimelockControllerTest:testCancellerCanCancelOperation() (gas: 3063422) +TimelockControllerTest:testCompleteOperationWithAssignExecutorRoleToZeroAddress() (gas: 122898) +TimelockControllerTest:testCompletePipelineOperationMinimumDelayUpdate() (gas: 71774) +TimelockControllerTest:testCompletePipelineOperationSetRoleAdmin() (gas: 98724) +TimelockControllerTest:testExecutorCanBatchExecute() (gas: 3048925) +TimelockControllerTest:testExecutorCanExecute() (gas: 29514) +TimelockControllerTest:testExecutorCannotBatchSchedule() (gas: 1485551) +TimelockControllerTest:testExecutorCannotCancel() (gas: 15471) +TimelockControllerTest:testExecutorCannotSchedule() (gas: 19179) +TimelockControllerTest:testFuzzBatchValue(uint256) (runs: 256, μ: 4650613, ~: 4650379) +TimelockControllerTest:testFuzzHashOperation(address,uint256,bytes,bytes32,bytes32) (runs: 256, μ: 10609, ~: 10586) +TimelockControllerTest:testFuzzHashOperationBatch(address[],uint256[],bytes[],bytes32,bytes32) (runs: 256, μ: 1839631, ~: 1839240) +TimelockControllerTest:testFuzzOperationValue(uint256) (runs: 256, μ: 111686, ~: 111452) +TimelockControllerTest:testHandleERC1155() (gas: 41559996) +TimelockControllerTest:testHandleERC721() (gas: 7161275) +TimelockControllerTest:testHashOperation() (gas: 12368) +TimelockControllerTest:testHashOperationBatch() (gas: 1525351) +TimelockControllerTest:testInitialSetup() (gas: 4314434) +TimelockControllerTest:testInvalidOperation() (gas: 10719) +TimelockControllerTest:testOperationAlreadyScheduled() (gas: 51498) +TimelockControllerTest:testOperationCancelFinished() (gas: 99524) +TimelockControllerTest:testOperationEqualAndGreaterMinimumDelay() (gas: 89452) +TimelockControllerTest:testOperationHasBeenExecuted() (gas: 97670) +TimelockControllerTest:testOperationHasNotBeenExecuted() (gas: 51393) +TimelockControllerTest:testOperationInsufficientDelay() (gas: 19279) +TimelockControllerTest:testOperationMinimumDelayUpdate() (gas: 61120) +TimelockControllerTest:testOperationOperationIsNotReady() (gas: 56852) +TimelockControllerTest:testOperationPendingIfExecuted() (gas: 96240) +TimelockControllerTest:testOperationPendingIfNotYetExecuted() (gas: 51457) +TimelockControllerTest:testOperationPredecessorInvalid() (gas: 61100) +TimelockControllerTest:testOperationPredecessorMultipleNotExecuted() (gas: 90448) +TimelockControllerTest:testOperationPredecessorNotExecuted() (gas: 96184) +TimelockControllerTest:testOperationPredecessorNotScheduled() (gas: 64493) +TimelockControllerTest:testOperationReadyAfterTheExecutionTime() (gas: 51992) +TimelockControllerTest:testOperationReadyBeforeTheExecutionTime() (gas: 51955) +TimelockControllerTest:testOperationReadyOnTheExecutionTime() (gas: 51829) +TimelockControllerTest:testOperationTargetRevert() (gas: 107399) +TimelockControllerTest:testOperationTimestampHasBeenExecuted() (gas: 96014) +TimelockControllerTest:testOperationTimestampHasNotBeenExecuted() (gas: 51231) +TimelockControllerTest:testProposerCanBatchSchedule() (gas: 3088163) +TimelockControllerTest:testProposerCanCancel() (gas: 20401) +TimelockControllerTest:testProposerCanSchedule() (gas: 74851) +TimelockControllerTest:testProposerCannotBatchExecute() (gas: 1489960) +TimelockControllerTest:testProposerCannotExecute() (gas: 23703) +TimelockControllerTest:testReturnsLaterMinimumDelayForCalls() (gas: 20803) +TimelockControllerTest:testRevertWhenNotTimelock() (gas: 9150) +TimelockControllerTest:testScheduleAndExecuteWithEmptySalt() (gas: 105496) +TimelockControllerTest:testScheduleAndExecuteWithNonEmptySalt() (gas: 108853) +TimelockControllerTest:testStrangerCannotBatchExecute() (gas: 748679) +TimelockControllerTest:testStrangerCannotBatchSchedule() (gas: 746487) +TimelockControllerTest:testStrangerCannotCancel() (gas: 11371) +TimelockControllerTest:testStrangerCannotExecute() (gas: 16466) +TimelockControllerTest:testStrangerCannotSchedule() (gas: 14251) TimelockControllerTest:testSupportsInterfaceInvalidInterfaceId() (gas: 8490) TimelockControllerTest:testSupportsInterfaceInvalidInterfaceIdGasCost() (gas: 9280) TimelockControllerTest:testSupportsInterfaceSuccess() (gas: 10814) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 25564277..1489154e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -3,7 +3,7 @@ name: 👮‍♂️ Sanity checks on: [push, pull_request, workflow_dispatch] concurrency: - group: ${{github.workflow}}-${{github.ref}} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -13,10 +13,10 @@ jobs: matrix: os: - ubuntu-latest + python_version: + - 3.12 architecture: - x64 - python_version: - - 3.11 node_version: - 20 @@ -64,7 +64,7 @@ jobs: uses: psf/black@stable with: options: "--check --verbose" - src: "./scripts" + src: "./lib/utils" codespell: runs-on: ${{ matrix.os }} @@ -107,8 +107,7 @@ jobs: - name: Validate URLs run: | - awesome_bot ./*.md src/snekmate/**/*.vy src/snekmate/**/interfaces/*.vy \ - test/**/*.sol test/**/interfaces/*.sol test/**/mocks/*.sol \ - test/**/scripts/*.js scripts/*.py --allow-dupe --allow-redirect \ - --request-delay 0.4 \ - --white-list https://www.wagmi.xyz,https://github.com/pcaversaccio/snekmate.git@,https://github.com/pcaversaccio/snekmate/releases/tag/v0.1.0,https://github.com/pcaversaccio/snekmate/blob/v0.1.0,https://github.com/pcaversaccio/snekmate/compare/v0.0.5...v0.1.0 + awesome_bot ./*.md src/snekmate/**/*.vy src/snekmate/**/mocks/*.vy src/snekmate/**/interfaces/*.vyi \ + test/**/*.sol test/**/interfaces/*.sol test/**/mocks/*.sol test/**/scripts/*.js lib/utils/*.sol lib/utils/*.py \ + --allow-dupe --allow-redirect --request-delay 0.4 \ + --white-list https://www.wagmi.xyz,https://github.com/pcaversaccio/snekmate.git@,https://github.com/pcaversaccio/snekmate/releases/tag/v0.1.0,https://github.com/pcaversaccio/snekmate/blob/v0.1.0,https://github.com/pcaversaccio/snekmate/compare/v0.0.5...v0.1.0,https://github.com/vyperlang/vyper/releases/tag/v0.4.0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d09b4784..389e5691 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -3,7 +3,7 @@ name: 🔍️ CodeQL on: [push, pull_request, workflow_dispatch] concurrency: - group: ${{github.workflow}}-${{github.ref}} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -35,4 +35,4 @@ jobs: - name: Perform CodeQL analysis uses: github/codeql-action/analyze@v3 with: - category: "/language:${{matrix.language}}" + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/halmos.yml b/.github/workflows/halmos.yml new file mode 100644 index 00000000..e6974437 --- /dev/null +++ b/.github/workflows/halmos.yml @@ -0,0 +1,88 @@ +name: 👁️ Halmos symbolic tests + +on: + schedule: + # Run every day at 03:30 UTC. + - cron: "30 3 * * *" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + halmos: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-latest + python_version: + - 3.12 + architecture: + - x64 + halmos: + - "--config test/halmos.toml" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python_version }} + architecture: ${{ matrix.architecture }} + + - name: Install Vyper + run: pip install git+https://github.com/vyperlang/vyper.git@master + + - name: Show the Vyper version + run: vyper --version + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Install `setuptools` + run: pip install setuptools + + - name: Install Halmos + run: pip install git+https://github.com/a16z/halmos.git@main + + - name: Show the Halmos version + run: halmos --version + + - name: Install Yices 2 SMT solver + run: | + sudo add-apt-repository ppa:sri-csl/formal-methods + sudo apt-get update + sudo apt-get install yices2 + + - name: Show the Foundry Halmos config + run: forge config + env: + FOUNDRY_PROFILE: halmos + + - name: Run Halmos ERC-20 symbolic tests + run: halmos --contract ERC20TestHalmos ${{ matrix.halmos }} + env: + FOUNDRY_PROFILE: halmos + + - name: Run Halmos ERC-721 symbolic tests + run: halmos --contract ERC721TestHalmos ${{ matrix.halmos }} + env: + FOUNDRY_PROFILE: halmos + + - name: Run Halmos ERC-1155 symbolic tests + run: halmos --contract ERC1155TestHalmos ${{ matrix.halmos }} + env: + FOUNDRY_PROFILE: halmos + + - name: Run Halmos math symbolic tests + run: halmos --contract MathTestHalmos ${{ matrix.halmos }} + env: + FOUNDRY_PROFILE: halmos diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index c1e3ff89..fc177f3a 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -17,10 +17,10 @@ jobs: matrix: os: - ubuntu-latest + python_version: + - 3.12 architecture: - x64 - python_version: - - 3.11 steps: - name: Checkout diff --git a/.github/workflows/publish-test-pypi.yml b/.github/workflows/publish-test-pypi.yml index 5718e4ca..644f0b02 100644 --- a/.github/workflows/publish-test-pypi.yml +++ b/.github/workflows/publish-test-pypi.yml @@ -14,10 +14,10 @@ jobs: matrix: os: - ubuntu-latest + python_version: + - 3.12 architecture: - x64 - python_version: - - 3.11 steps: - name: Checkout diff --git a/.github/workflows/test-contracts.yml b/.github/workflows/test-contracts.yml index e97566c5..55c90201 100644 --- a/.github/workflows/test-contracts.yml +++ b/.github/workflows/test-contracts.yml @@ -3,7 +3,7 @@ name: 🕵️‍♂️ Test smart contracts on: [push, pull_request, workflow_dispatch] concurrency: - group: ${{github.workflow}}-${{github.ref}} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -13,12 +13,14 @@ jobs: matrix: os: - ubuntu-latest + python_version: + - 3.12 architecture: - x64 - python_version: - - 3.11 node_version: - 20 + echidna: + - "--config test/echidna.yaml" steps: - name: Checkout @@ -33,18 +35,18 @@ jobs: architecture: ${{ matrix.architecture }} - name: Install Vyper - run: pip install vyper + run: pip install git+https://github.com/vyperlang/vyper.git@master - - name: Check userdoc and devdoc compilation - run: python scripts/compile.py + - name: Show the Vyper version + run: vyper --version - - name: Setup Ape - uses: ApeWorX/github-action@v2 - with: - python-version: ${{ matrix.python_version }} + # - name: Setup Ape + # uses: ApeWorX/github-action@v2 + # with: + # python-version: ${{ matrix.python_version }} - - name: Check Ape compilation - run: ape compile + # - name: Check Ape compilation + # run: ape compile - name: Install pnpm uses: pnpm/action-setup@v3 @@ -97,3 +99,32 @@ jobs: run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY env: FOUNDRY_PROFILE: default + + - name: Install Homebrew + uses: Homebrew/actions/setup-homebrew@master + + - name: Install Echidna + run: brew install echidna + + - name: Show the Echidna version + run: echidna --version + + - name: Show the Foundry Echidna config + run: forge config + env: + FOUNDRY_PROFILE: echidna + + - name: Compile the Echidna test contracts + run: forge build --build-info + env: + FOUNDRY_PROFILE: echidna + + - name: Run Echidna ERC-20 property tests + run: echidna test/tokens/echidna/ERC20Properties.sol --contract CryticERC20ExternalHarness ${{ matrix.echidna }} + env: + FOUNDRY_PROFILE: echidna + + - name: Run Echidna ERC-721 property tests + run: echidna test/tokens/echidna/ERC721Properties.sol --contract CryticERC721ExternalHarness ${{ matrix.echidna }} + env: + FOUNDRY_PROFILE: echidna diff --git a/.gitignore b/.gitignore index 7a633eeb..5c5e1c44 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,7 @@ dist # Ape build files .build + +# Echidna files +echidna-corpus +crytic-export diff --git a/.gitmodules b/.gitmodules index ac883613..f706870d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,12 +13,21 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std.git +[submodule "lib/properties"] + path = lib/properties + url = https://github.com/crytic/properties.git [submodule "lib/create-util"] path = lib/create-util url = https://github.com/pcaversaccio/create-util.git [submodule "lib/erc4626-tests"] path = lib/erc4626-tests url = https://github.com/a16z/erc4626-tests.git +[submodule "lib/FreshCryptoLib"] + path = lib/FreshCryptoLib + url = https://github.com/rdubois-crypto/FreshCryptoLib.git +[submodule "lib/halmos-cheatcodes"] + path = lib/halmos-cheatcodes + url = https://github.com/a16z/halmos-cheatcodes.git [submodule "lib/solidity-bytes-utils"] path = lib/solidity-bytes-utils url = https://github.com/GNSPS/solidity-bytes-utils.git diff --git a/.prettierignore b/.prettierignore index 136923a9..612a610e 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,10 +4,15 @@ lib/solady lib/solmate lib/prb-test lib/forge-std +lib/properties lib/create-util lib/erc4626-tests +lib/FreshCryptoLib +lib/halmos-cheatcodes lib/solidity-bytes-utils lib/openzeppelin-contracts +echidna-corpus +crytic-export cache out dist diff --git a/.solhintignore b/.solhintignore index 136923a9..612a610e 100644 --- a/.solhintignore +++ b/.solhintignore @@ -4,10 +4,15 @@ lib/solady lib/solmate lib/prb-test lib/forge-std +lib/properties lib/create-util lib/erc4626-tests +lib/FreshCryptoLib +lib/halmos-cheatcodes lib/solidity-bytes-utils lib/openzeppelin-contracts +echidna-corpus +crytic-export cache out dist diff --git a/CHANGELOG.md b/CHANGELOG.md index 1de9b9ba..f085c479 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,66 @@ # 🕓 Changelog -## [`0.1.0`](https://github.com/pcaversaccio/snekmate/releases/tag/v0.0.1) (Unreleased) +## [`0.1.0`](https://github.com/pcaversaccio/snekmate/releases/tag/v0.1.0) (Unreleased) + +> [!IMPORTANT] +> The aggregating pull request used to implement the subsequent changes is [#207](https://github.com/pcaversaccio/snekmate/pull/207). + +### 💥 New Features + +- **Authentication** + - [`ownable`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/auth/ownable.vy): Make `ownable` module-friendly. ([#218](https://github.com/pcaversaccio/snekmate/pull/218)) + - [`ownable_2step`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/auth/ownable_2step.vy): Make `ownable_2step` module-friendly. ([#219](https://github.com/pcaversaccio/snekmate/pull/219)) + - [`access_control`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/auth/access_control.vy): Make `access_control` module-friendly. ([#216](https://github.com/pcaversaccio/snekmate/pull/216)) +- **Extensions** + - [`erc2981`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/extensions/erc2981.vy): Make `erc2981` module-friendly. ([#233](https://github.com/pcaversaccio/snekmate/pull/233)) + - [`erc4626`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/extensions/erc4626.vy): Make `erc4626` module-friendly. ([#236](https://github.com/pcaversaccio/snekmate/pull/236)) +- **Governance** + - [`timelock_controller`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/governance/timelock_controller.vy): Make `timelock_controller` module-friendly. ([#220](https://github.com/pcaversaccio/snekmate/pull/220)) +- **Tokens** + - [`erc20`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/tokens/erc20.vy): Make `erc20` module-friendly. ([#234](https://github.com/pcaversaccio/snekmate/pull/234)) + - [`erc721`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/tokens/erc721.vy): Make `erc721` module-friendly. ([#237](https://github.com/pcaversaccio/snekmate/pull/237)) + - [`erc1155`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/tokens/erc1155.vy): Make `erc1155` module-friendly. ([#238](https://github.com/pcaversaccio/snekmate/pull/238)) +- **Utility Functions** + - [`base64`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/base64.vy): Make `base64` module-friendly. ([#222](https://github.com/pcaversaccio/snekmate/pull/222)) + - [`batch_distributor`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/batch_distributor.vy): Make `batch_distributor` module-friendly. ([#223](https://github.com/pcaversaccio/snekmate/pull/223)) + - [`create_address`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/create_address.vy): Make `create_address` module-friendly. ([#224](https://github.com/pcaversaccio/snekmate/pull/224)) + - [`create2_address`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/create2_address.vy): Make `create2_address` module-friendly. ([#225](https://github.com/pcaversaccio/snekmate/pull/225)) + - [`ecdsa`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/ecdsa.vy): Make `ecdsa` module-friendly. ([#227](https://github.com/pcaversaccio/snekmate/pull/227)) + - [`p256`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/p256.vy): Add NIST P-256 (a.k.a. secp256r1) ECDSA verification function. ([#243](https://github.com/pcaversaccio/snekmate/pull/243)) + - [`message_hash_utils`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/message_hash_utils.vy): Move the `ecdsa` message hash methods to a separate `message_hash_utils` library module. ([#227](https://github.com/pcaversaccio/snekmate/pull/227)) + - [`signature_checker`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/signature_checker.vy): Make `signature_checker` module-friendly. ([#228](https://github.com/pcaversaccio/snekmate/pull/228)) + - [`eip712_domain_separator`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/eip712_domain_separator.vy): Make `eip712_domain_separator` module-friendly. ([#229](https://github.com/pcaversaccio/snekmate/pull/229)) + - [`math`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/math.vy): Make `math` module-friendly. ([#230](https://github.com/pcaversaccio/snekmate/pull/230)) + - [`merkle_proof_verification`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/merkle_proof_verification.vy): Make `merkle_proof_verification` module-friendly. ([#231](https://github.com/pcaversaccio/snekmate/pull/231)) + - [`multicall`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/multicall.vy): Make `multicall` module-friendly. ([#232](https://github.com/pcaversaccio/snekmate/pull/232)) +- **🐍Vyper Contract Deployer** + - [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/lib/utils/VyperDeployer.sol): Improve error message in the event of a 🐍Vyper compilation error. ([#219](https://github.com/pcaversaccio/snekmate/pull/219)) + +### 🥢 Test Coverage + +- **Tokens** + - [`erc20`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/tokens/erc20.vy): + - Add `echidna`-based `erc20` property tests. ([#239](https://github.com/pcaversaccio/snekmate/pull/239)) + - Add `halmos`-based `erc20` symbolic tests. ([#240](https://github.com/pcaversaccio/snekmate/pull/240)) + - [`erc721`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/tokens/erc721.vy): + - Add `echidna`-based `erc721` property tests. ([#239](https://github.com/pcaversaccio/snekmate/pull/239)) + - Add `halmos`-based `erc721` symbolic tests. ([#240](https://github.com/pcaversaccio/snekmate/pull/240)) + - [`erc1155`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/tokens/erc1155.vy): Add `halmos`-based `erc1155` symbolic tests. ([#240](https://github.com/pcaversaccio/snekmate/pull/240)) +- **Utility Functions** + - [`math`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/math.vy): Add `halmos`-based `math` symbolic tests. ([#240](https://github.com/pcaversaccio/snekmate/pull/240)) + +### ❗️ Breaking Changes + +- The file names of 🐍 snekmate module and mock contracts use the _snake case_ notation (e.g. `my_module.vy` or `my_module_mock.vy`), whilst the 🐍Vyper interface files `.vyi` use the _Pascal case_ notation prefixed with `I` (e.g. `IMyInterface.vyi`). ([#242](https://github.com/pcaversaccio/snekmate/pull/242)) +- The mathematical utility functions `_log_2`, `_log_10`, and `_log_256` are renamed to `_log2`, `_log10`, and `_log256`. ([#242](https://github.com/pcaversaccio/snekmate/pull/242)) +- All 🐍 snekmate contracts now target the new 🐍Vyper [default EVM version](https://github.com/vyperlang/vyper/pull/4029) `cancun` ([#245](https://github.com/pcaversaccio/snekmate/pull/245)). If you intend to deploy on an EVM chain with no `cancun` support, you must compile — using the `shanghai` EVM version as an example — the main contract that uses the 🐍 snekmate module contracts with the `--evm-version shanghai` option; e.g. `vyper --evm-version shanghai src/snekmate/tokens/mocks/erc20_mock.vy`, or add the `# pragma evm-version shanghai` directive to the main contract that uses the 🐍 snekmate module contracts: + +```vyper +# pragma version ~=0.4.0 +# pragma evm-version shanghai + +... +``` ### 👀 Full Changelog @@ -61,8 +121,8 @@ - [`ERC1155`](https://github.com/pcaversaccio/snekmate/blob/v0.0.3/src/tokens/ERC1155.vy): Optimise the `set_minter` function to save one `SLOAD`. ([#154](https://github.com/pcaversaccio/snekmate/pull/154)) - **Utility Functions** - [`Math`](https://github.com/pcaversaccio/snekmate/blob/v0.0.3/src/utils/Math.vy): Optimise the method used to factor powers of two out of the denominator in `mul_div`. ([#153](https://github.com/pcaversaccio/snekmate/pull/153)) -- **Vyper Contract Deployer** - - [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.0.3/lib/utils/VyperDeployer.sol): If you want to leverage 🐍 snekmate's [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.0.3/lib/utils/VyperDeployer.sol) contract for your own testing, ensure that you compile the Vyper contracts with the same EVM version as configured in your `foundry.toml` file. The [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.0.3/lib/utils/VyperDeployer.sol) contract offers two overloaded `deployContract` functions that allow the configuration of the target EVM version. Please note that since Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) the default EVM version is set to `shanghai`. ([#161](https://github.com/pcaversaccio/snekmate/pull/161)) +- **🐍Vyper Contract Deployer** + - [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.0.3/lib/utils/VyperDeployer.sol): If you want to leverage 🐍 snekmate's [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.0.3/lib/utils/VyperDeployer.sol) contract for your own testing, ensure that you compile the 🐍Vyper contracts with the same EVM version as configured in your `foundry.toml` file. The [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.0.3/lib/utils/VyperDeployer.sol) contract offers two overloaded `deployContract` functions that allow the configuration of the target EVM version. Please note that since 🐍Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) the default EVM version is set to `shanghai`. ([#161](https://github.com/pcaversaccio/snekmate/pull/161)) ### 🥢 Test Coverage @@ -71,7 +131,7 @@ ### ❗️ Breaking Change -- All 🐍 snekmate contracts now target the Vyper version [`0.3.10`](https://github.com/vyperlang/vyper/releases/tag/v0.3.10) ([#164](https://github.com/pcaversaccio/snekmate/pull/164)). It is strongly recommended to upgrade accordingly your local Vyper version prior to using the 🐍 snekmate contracts. **Important:** The default EVM version since Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) is set to `shanghai` (i.e. the EVM includes the [`PUSH0`](https://eips.ethereum.org/EIPS/eip-3855) instruction). If you intend to deploy on an EVM chain with no `PUSH0` support, you must compile the 🐍 snekmate contracts with the `--evm-version paris` option; e.g. `vyper --evm-version paris utils/Math.vy`, or add the `# pragma evm-version paris` directive to the 🐍 snekmate contracts: +- All 🐍 snekmate contracts now target the 🐍Vyper version [`0.3.10`](https://github.com/vyperlang/vyper/releases/tag/v0.3.10) ([#164](https://github.com/pcaversaccio/snekmate/pull/164)). It is strongly recommended to upgrade accordingly your local 🐍Vyper version prior to using the 🐍 snekmate contracts. **Important:** The default EVM version since 🐍Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) is set to `shanghai` (i.e. the EVM includes the [`PUSH0`](https://eips.ethereum.org/EIPS/eip-3855) instruction). If you intend to deploy on an EVM chain with no `PUSH0` support, you must compile the 🐍 snekmate contracts with the `--evm-version paris` option; e.g. `vyper --evm-version paris utils/Math.vy`, or add the `# pragma evm-version paris` directive to the 🐍 snekmate contracts: ```vyper # pragma version ^0.3.10 @@ -90,7 +150,7 @@ implements: ERC20 ... ``` -> The `# pragma optimize` directive has also been added in Vyper version [`0.3.10`](https://github.com/vyperlang/vyper/releases/tag/v0.3.10) (see PR [#3493](https://github.com/vyperlang/vyper/pull/3493)). Please refer to [here](https://docs.vyperlang.org/en/stable/compiling-a-contract.html#compiler-optimization-modes) to learn more about the different options `none`, `codesize`, and `gas` (default). +> The `# pragma optimize` directive has also been added in 🐍Vyper version [`0.3.10`](https://github.com/vyperlang/vyper/releases/tag/v0.3.10) (see PR [#3493](https://github.com/vyperlang/vyper/pull/3493)). Please refer to [here](https://docs.vyperlang.org/en/stable/compiling-a-contract.html#compiler-optimization-modes) to learn more about the different options `none`, `codesize`, and `gas` (default). ### 👀 Full Changelog @@ -114,26 +174,26 @@ implements: ERC20 ### ♻️ Refactoring - **General** - - All 🐍 snekmate contracts are now guaranteed to compile with the Vyper CLI flags `userdoc` and `devdoc`, and, if using the [Ape framework](https://github.com/ApeWorX/ape), with `ape compile`. ([#126](https://github.com/pcaversaccio/snekmate/pull/126)) + - All 🐍 snekmate contracts are now guaranteed to compile with the 🐍Vyper CLI flags `userdoc` and `devdoc`, and, if using the [Ape framework](https://github.com/ApeWorX/ape), with `ape compile`. ([#126](https://github.com/pcaversaccio/snekmate/pull/126)) - **Extensions** - [`ERC4626`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/extensions/ERC4626.vy): - Add `implements` interface `ERC20Detailed` and `ERC4626`. ([#125](https://github.com/pcaversaccio/snekmate/pull/125)) - - Use of the ternary operator introduced in Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) in the constructor for the `immutable` variable assignment of `_UNDERLYING_DECIMALS` instead of an `if-else` statement. ([#128](https://github.com/pcaversaccio/snekmate/pull/128)) + - Use of the ternary operator introduced in 🐍Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) in the constructor for the `immutable` variable assignment of `_UNDERLYING_DECIMALS` instead of an `if-else` statement. ([#128](https://github.com/pcaversaccio/snekmate/pull/128)) - **Tokens** - [`ERC20`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/tokens/ERC20.vy): Add `implements` interface `ERC20Detailed`. ([#125](https://github.com/pcaversaccio/snekmate/pull/125)) - [`ERC721`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/tokens/ERC721.vy): Add `implements` interface `IERC721Metadata`. ([#125](https://github.com/pcaversaccio/snekmate/pull/125)) - **Utility Functions** - - [`Base64`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/utils/Base64.vy): Use the shift operators `>>` and `<<` introduced in Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) instead of the `shift` instruction. ([#127](https://github.com/pcaversaccio/snekmate/pull/127)) - - [`ECDSA`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/utils/ECDSA.vy): Use the shift operators `>>` and `<<` introduced in Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) instead of the `shift` instruction. ([#127](https://github.com/pcaversaccio/snekmate/pull/127)) - - [`SignatureChecker`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/utils/SignatureChecker.vy): Use the shift operators `>>` and `<<` introduced in Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) instead of the `shift` instruction. ([#127](https://github.com/pcaversaccio/snekmate/pull/127)) + - [`Base64`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/utils/Base64.vy): Use the shift operators `>>` and `<<` introduced in 🐍Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) instead of the `shift` instruction. ([#127](https://github.com/pcaversaccio/snekmate/pull/127)) + - [`ECDSA`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/utils/ECDSA.vy): Use the shift operators `>>` and `<<` introduced in 🐍Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) instead of the `shift` instruction. ([#127](https://github.com/pcaversaccio/snekmate/pull/127)) + - [`SignatureChecker`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/utils/SignatureChecker.vy): Use the shift operators `>>` and `<<` introduced in 🐍Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) instead of the `shift` instruction. ([#127](https://github.com/pcaversaccio/snekmate/pull/127)) - [`Math`](https://github.com/pcaversaccio/snekmate/blob/v0.0.2/src/utils/Math.vy): - Use directly 🐍 snekmate's [`log_2`](https://github.com/pcaversaccio/snekmate/blob/v0.0.1/src/utils/Math.vy#L202) function in the internal calculation of `wad_cbrt`. ([#91](https://github.com/pcaversaccio/snekmate/pull/91)) - - Use the shift operators `>>` and `<<` introduced in Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) instead of the `shift` instruction. ([#127](https://github.com/pcaversaccio/snekmate/pull/127)) - - Use of the ternary operator introduced in Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) in the function `ceil_div` instead of an `if-else` statement. ([#128](https://github.com/pcaversaccio/snekmate/pull/128)) + - Use the shift operators `>>` and `<<` introduced in 🐍Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) instead of the `shift` instruction. ([#127](https://github.com/pcaversaccio/snekmate/pull/127)) + - Use of the ternary operator introduced in 🐍Vyper [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) in the function `ceil_div` instead of an `if-else` statement. ([#128](https://github.com/pcaversaccio/snekmate/pull/128)) ### ❗️ Breaking Change -- All 🐍 snekmate contracts now target the Vyper version [`0.3.9`](https://github.com/vyperlang/vyper/releases/tag/v0.3.9). It is strongly recommended to upgrade accordingly your local Vyper version prior to using the 🐍 snekmate contracts. **Important:** The default EVM version since Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) is set to `shanghai` (i.e. the EVM includes the [`PUSH0`](https://eips.ethereum.org/EIPS/eip-3855) instruction). If you intend to deploy on an EVM chain with no `PUSH0` support, you must compile the 🐍 snekmate contracts with the `--evm-version paris` option; e.g. `vyper --evm-version paris utils/Math.vy`. ([#122](https://github.com/pcaversaccio/snekmate/pull/122)) +- All 🐍 snekmate contracts now target the 🐍Vyper version [`0.3.9`](https://github.com/vyperlang/vyper/releases/tag/v0.3.9). It is strongly recommended to upgrade accordingly your local 🐍Vyper version prior to using the 🐍 snekmate contracts. **Important:** The default EVM version since 🐍Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) is set to `shanghai` (i.e. the EVM includes the [`PUSH0`](https://eips.ethereum.org/EIPS/eip-3855) instruction). If you intend to deploy on an EVM chain with no `PUSH0` support, you must compile the 🐍 snekmate contracts with the `--evm-version paris` option; e.g. `vyper --evm-version paris utils/Math.vy`. ([#122](https://github.com/pcaversaccio/snekmate/pull/122)) ### 👀 Full Changelog diff --git a/GUIDELINES.md b/GUIDELINES.md index 6137574b..924a96d7 100644 --- a/GUIDELINES.md +++ b/GUIDELINES.md @@ -14,7 +14,7 @@ Any addition or change to the code must be accompanied by relevant and comprehen The test suite should run automatically for each change in the repository, and for pull requests, the tests must succeed before merging. -Please consider writing [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. fuzzing), and invariant tests for all contracts, if applicable. +Please consider writing [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. stateless fuzzing), and invariant tests (i.e. stateful fuzzing) for all contracts, if applicable. ## 🪅 Code Style @@ -50,6 +50,7 @@ Branch names do not matter, and commit messages within a PR are mostly not impor ## 🐍Vyper Conventions +- The file names of module and mock contracts use the _snake case_ notation (e.g. `my_module.vy` or `my_module_mock.vy`), whilst the 🐍Vyper interface files `.vyi` use the _Pascal case_ notation prefixed with `I` (e.g. `IMyInterface.vyi`). - The names of `constant`, `immutable`, and state variables, functions, and function parameters use the _snake case_ notation (e.g. `my_function`) if no other notation is enforced via an EIP standard. In particular, `constant` and `immutable` variable names use the _screaming snake case_ notation (e.g. `DEFAULT_CONSTANT`) if no other notation is enforced via an EIP standard. - `internal` `constant`, `immutable`, state variables and functions must have an underscore prefix: @@ -71,7 +72,10 @@ def _as_singleton_array(element: uint256) -> DynArray[uint256, 1]: - All functions should be provided with full [NatSpec](https://docs.vyperlang.org/en/latest/natspec.html) comments containing the tags `@dev`, `@notice` (if applicable), `@param` for each function parameter, and `@return` if a return statement is present. - Please note the following order of layout: - Version pragma statement - - Interface imports + - 🐍Vyper built-in interface imports + - Custom interface imports + - Module imports + - Module exports - `public` constants - `internal` constants - `public` immutables diff --git a/MANIFEST.in b/MANIFEST.in index 14c5d291..3ef7d7fb 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include LICENSE README.md CHANGELOG.md pyproject.toml graft src +prune src/snekmate/**/mocks diff --git a/README.md b/README.md index 9800f547..8bf7ee48 100644 --- a/README.md +++ b/README.md @@ -18,45 +18,74 @@ src └── snekmate ├── auth - │ ├── Ownable — "Owner-Based Access Control Functions" - │ ├── Ownable2Step — "2-Step Ownership Transfer Functions" - │ ├── AccessControl — "Multi-Role-Based Access Control Functions" - │ └── interfaces - │ └── IAccessControl — "AccessControl Interface Definition" + │ ├── ownable — "Owner-Based Access Control Functions" + │ ├── ownable_2step — "2-Step Ownership Transfer Functions" + │ ├── access_control — "Multi-Role-Based Access Control Functions" + │ ├── interfaces + │ │ └── IAccessControl — "AccessControl Interface Definition" + │ └── mocks + │ ├── ownable_mock — "`ownable` Module Reference Implementation" + │ ├── ownable_2step_mock — "`ownable_2step` Module Reference Implementation" + │ └── access_control_mock — "`access_control` Module Reference Implementation" ├── extensions - │ ├── ERC2981 — "ERC-721 and ERC-1155 Compatible ERC-2981 Reference Implementation" - │ ├── ERC4626 — "Modern and Gas-Efficient ERC-4626 Tokenised Vault Implementation" - │ └── interfaces - │ └── IERC2981 — "EIP-2981 Interface Definition" + │ ├── erc2981 — "ERC-721 and ERC-1155 Compatible ERC-2981 Reference Implementation" + │ ├── erc4626 — "Modern and Gas-Efficient ERC-4626 Tokenised Vault Implementation" + │ ├── interfaces + │ │ └── IERC2981 — "EIP-2981 Interface Definition" + │ └── mocks + │ ├── erc2981_mock — "`erc2981` Module Reference Implementation" + │ └── erc4626_mock — "`erc4626` Module Reference Implementation" ├── governance - │ └── TimelockController — "Multi-Role-Based Timelock Controller Reference Implementation" + │ ├── timelock_controller — "Multi-Role-Based Timelock Controller Reference Implementation" + │ └── mocks + │ └── timelock_controller_mock — "`timelock_controller` Module Reference Implementation" ├── tokens - │ ├── ERC20 — "Modern and Gas-Efficient ERC-20 + EIP-2612 Implementation" - │ ├── ERC721 — "Modern and Gas-Efficient ERC-721 + EIP-4494 Implementation" - │ ├── ERC1155 — "Modern and Gas-Efficient ERC-1155 Implementation" - │ └── interfaces - │ ├── IERC20Permit — "EIP-2612 Interface Definition" - │ ├── IERC721Enumerable — "EIP-721 Optional Enumeration Interface Definition" - │ ├── IERC721Metadata — "EIP-721 Optional Metadata Interface Definition" - │ ├── IERC721Permit — "EIP-4494 Interface Definition" - │ ├── IERC721Receiver — "EIP-721 Token Receiver Interface Definition" - │ ├── IERC1155 — "EIP-1155 Interface Definition" - │ ├── IERC1155MetadataURI — "EIP-1155 Optional Metadata Interface Definition" - │ ├── IERC1155Receiver — "EIP-1155 Token Receiver Interface Definition" - │ └── IERC4906 — "EIP-4906 Interface Definition" + │ ├── erc20 — "Modern and Gas-Efficient ERC-20 + EIP-2612 Implementation" + │ ├── erc721 — "Modern and Gas-Efficient ERC-721 + EIP-4494 Implementation" + │ ├── erc1155 — "Modern and Gas-Efficient ERC-1155 Implementation" + │ ├── interfaces + │ │ ├── IERC20Permit — "EIP-2612 Interface Definition" + │ │ ├── IERC721Enumerable — "EIP-721 Optional Enumeration Interface Definition" + │ │ ├── IERC721Metadata — "EIP-721 Optional Metadata Interface Definition" + │ │ ├── IERC721Permit — "EIP-4494 Interface Definition" + │ │ ├── IERC721Receiver — "EIP-721 Token Receiver Interface Definition" + │ │ ├── IERC1155 — "EIP-1155 Interface Definition" + │ │ ├── IERC1155MetadataURI — "EIP-1155 Optional Metadata Interface Definition" + │ │ ├── IERC1155Receiver — "EIP-1155 Token Receiver Interface Definition" + │ │ └── IERC4906 — "EIP-4906 Interface Definition" + │ └── mocks + │ ├── erc20_mock — "`erc20` Module Reference Implementation" + │ ├── erc721_mock — "`erc721` Module Reference Implementation" + │ └── erc1155_mock — "`erc1155` Module Reference Implementation" └── utils - ├── Base64 — "Base64 Encoding and Decoding Functions" - ├── BatchDistributor — "Batch Sending Both Native and ERC-20 Tokens" - ├── CreateAddress — "`CREATE` EVM Opcode Utility Function for Address Calculation" - ├── Create2Address — "`CREATE2` EVM Opcode Utility Functions for Address Calculations" - ├── ECDSA — "Elliptic Curve Digital Signature Algorithm (ECDSA) Functions" - ├── SignatureChecker — "ECDSA and EIP-1271 Signature Verification Functions" - ├── EIP712DomainSeparator — "EIP-712 Domain Separator" - ├── Math — "Standard Mathematical Utility Functions" - ├── MerkleProofVerification — "Merkle Tree Proof Verification Functions" - ├── Multicall — "Multicall Functions" - └── interfaces - └── IERC5267 — "EIP-5267 Interface Definition" + ├── base64 — "Base64 Encoding and Decoding Functions" + ├── batch_distributor — "Batch Sending Both Native and ERC-20 Tokens" + ├── create_address — "`CREATE` EVM Opcode Utility Function for Address Calculation" + ├── create2_address — "`CREATE2` EVM Opcode Utility Functions for Address Calculations" + ├── ecdsa — "Elliptic Curve Digital Signature Algorithm (ECDSA) Secp256k1-Based Functions" + ├── p256 — "Elliptic Curve Digital Signature Algorithm (ECDSA) Secp256r1-Based Functions" + ├── message_hash_utils — "Signature Message Hash Utility Functions" + ├── signature_checker — "ECDSA and EIP-1271 Signature Verification Functions" + ├── eip712_domain_separator — "EIP-712 Domain Separator" + ├── math — "Standard Mathematical Utility Functions" + ├── merkle_proof_verification — "Merkle Tree Proof Verification Functions" + ├── multicall — "Multicall Functions" + ├── interfaces + │ ├── IERC1271 — "EIP-1271 Interface Definition" + │ └── IERC5267 — "EIP-5267 Interface Definition" + └── mocks + ├── base64_mock — "`base64` Module Reference Implementation" + ├── batch_distributor_mock — "`batch_distributor` Module Reference Implementation" + ├── create_address_mock — "`create_address` Module Reference Implementation" + ├── create2_address_mock — "`create2_address` Module Reference Implementation" + ├── ecdsa_mock — "`ecdsa` Module Reference Implementation" + ├── p256_mock — "`p256` Module Reference Implementation" + ├── message_hash_utils_mock — "`message_hash_utils` Module Reference Implementation" + ├── signature_checker_mock — "`signature_checker` Module Reference Implementation" + ├── eip712_domain_separator_mock — "`eip712_domain_separator` Module Reference Implementation" + ├── math_mock — "`math` Module Reference Implementation" + ├── merkle_proof_verification_mock — "`merkle_proof_verification` Module Reference Implementation" + └── multicall_mock — "`multicall` Module Reference Implementation" ``` ## 🎛 Installation @@ -74,7 +103,8 @@ You can install 🐍 snekmate via submodules using [Foundry](https://github.com/ forge install pcaversaccio/snekmate ``` -> If you want to leverage 🐍 snekmate's [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract for your own testing, ensure that you compile the Vyper contracts with the same EVM version as configured in your `foundry.toml` file. The [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract offers two overloaded `deployContract` functions that allow the configuration of the target EVM version. Please note that since Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) the default EVM version is set to `shanghai`. +> [!NOTE] +> If you want to leverage 🐍 snekmate's [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract for your own testing, ensure that you compile the 🐍Vyper contracts with the same EVM version as configured in your `foundry.toml` file. The [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract offers two overloaded `deployContract` functions that allow the configuration of the target EVM version. Please note that since 🐍Vyper version [`0.4.0`](https://github.com/vyperlang/vyper/releases/tag/v0.4.0) the default EVM version is set to `cancun`. Furthermore, the [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract relies on the Python script [`compile.py`](./lib/utils/compile.py) for successful compilation and deployment. Always use the [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract alongside with the aforementioned script. ### 2️⃣ PyPI @@ -109,37 +139,80 @@ pnpm add --save-dev snekmate > [!CAUTION] > It is possible to install the latest versions of `main` or any other branch locally via `pip install git+https://github.com/pcaversaccio/snekmate.git@` or `forge install pcaversaccio/snekmate && forge update`. Each branch, **including the `main` branch**, must be understood as a development branch that should be avoided in favour of tagged releases. The release process includes security measures that the repository branches do not guarantee. +## 🔧 Usage + +🐍Vyper favours code reuse through composition rather than inheritance (Solidity inheritance makes it easy to break the [Liskov Substitution Principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle)). A 🐍Vyper module encapsulates everything required for code reuse, from type and function declarations to state. **All 🐍 snekmate contracts are 🐍Vyper modules.** Thus, many of the 🐍 snekmate contracts do not compile independently, but you must `import` and `initializes` them. Please note that if a module is _stateless_, it does not require the keyword `initializes` (or `uses`) for initialisation (or usage). Each module contract has an associated mock contract in the `mock/` directory, which is part of the associated contract subdirectory. These mock contracts are very illustrative of how 🐍 snekmate contracts can be used as 🐍Vyper modules. + +> [!IMPORTANT] +> All 🐍 snekmate contracts are very well documented in the form of general code and [NatSpec](https://docs.vyperlang.org/en/latest/natspec.html) comments. There are no shortcuts – if you are importing specific logic, read the documentation! + +Please read [here](https://docs.vyperlang.org/en/latest/using-modules.html) to learn more about using 🐍Vyper modules. + ## 👩🏼‍⚖️ Tests -This repository contains [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. fuzzing), and invariant tests for all contracts, if applicable. All tests are run as part of the CI pipeline [`test-contracts`](./.github/workflows/test-contracts.yml). +This repository contains [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. stateless fuzzing), and invariant tests (i.e. stateful fuzzing) for all contracts, if applicable. All tests are run as part of the CI pipeline [`test-contracts`](./.github/workflows/test-contracts.yml). > [!NOTE] > An _invariant_ is a property of a program that should always hold true. Fuzzing is a way of checking whether the invariant is falsifiable. -| **Contract** | **Unit Tests** | **Property-Based Tests** | **Invariant Tests** | -| :------------------------ | :------------: | :----------------------: | :-----------------: | -| `Ownable` | ✅ | ✅ | ✅ | -| `Ownable2Step` | ✅ | ✅ | ✅ | -| `AccessControl` | ✅ | ✅ | ✅ | -| `ERC2981` | ✅ | ✅ | ✅ | -| `ERC4626` | ✅ | ✅ | ✅ | -| `TimelockController` | ✅ | ✅ | ✅ | -| `ERC20` | ✅ | ✅ | ✅ | -| `ERC721` | ✅ | ✅ | ✅ | -| `ERC1155` | ✅ | ✅ | ✅ | -| `Base64` | ✅ | ❌ | ❌ | -| `BatchDistributor` | ✅ | ✅ | ✅ | -| `CreateAddress` | ✅ | ✅ | ❌ | -| `Create2Address` | ✅ | ✅ | ❌ | -| `ECDSA` | ✅ | ✅ | ❌ | -| `SignatureChecker` | ✅ | ✅ | ❌ | -| `EIP712DomainSeparator` | ✅ | ✅ | ❌ | -| `Math` | ✅ | ✅ | ❌ | -| `MerkleProofVerification` | ✅ | ✅ | ❌ | -| `Multicall` | ✅ | ❌ | ❌ | +| **Contract** | **Unit Tests** | **Property-Based Tests** | **Invariant Tests** | +| :-------------------------- | :------------: | :----------------------: | :-----------------: | +| `ownable` | ✅ | ✅ | ✅ | +| `ownable_2step` | ✅ | ✅ | ✅ | +| `access_control` | ✅ | ✅ | ✅ | +| `erc2981` | ✅ | ✅ | ✅ | +| `erc4626` | ✅ | ✅ | ✅ | +| `timelock_controller` | ✅ | ✅ | ✅ | +| `erc20` | ✅ | ✅ | ✅ | +| `erc721` | ✅ | ✅ | ✅ | +| `erc1155` | ✅ | ✅ | ✅ | +| `base64` | ✅ | ❌ | ❌ | +| `batch_distributor` | ✅ | ✅ | ✅ | +| `create_address` | ✅ | ✅ | ❌ | +| `create2_address` | ✅ | ✅ | ❌ | +| `ecdsa` | ✅ | ✅ | ❌ | +| `p256` | ✅ | ✅ | ❌ | +| `message_hash_utils` | ✅ | ✅ | ❌ | +| `signature_checker` | ✅ | ✅ | ❌ | +| `eip712_domain_separator` | ✅ | ✅ | ❌ | +| `math` | ✅ | ✅ | ❌ | +| `merkle_proof_verification` | ✅ | ✅ | ❌ | +| `multicall` | ✅ | ❌ | ❌ | ✅ Test Type Implemented   ❌ Test Type Not Implemented +Furthermore, the [`echidna`](https://github.com/crytic/echidna)-based [property](https://github.com/crytic/properties) tests for the [`erc20`](./src/snekmate/tokens/ERC20.vy) and [`erc721`](./src/snekmate/tokens/ERC721.vy) contracts are available in the [`test/tokens/echidna/`](./test/tokens/echidna) directory. You can run the tests by invoking: + +```console +# Run Echidna ERC-20 property tests. +~$ FOUNDRY_PROFILE=echidna echidna test/tokens/echidna/ERC20Properties.sol --contract CryticERC20ExternalHarness --config test/echidna.yaml + +# Run Echidna ERC-721 property tests. +~$ FOUNDRY_PROFILE=echidna echidna test/tokens/echidna/ERC721Properties.sol --contract CryticERC721ExternalHarness --config test/echidna.yaml +``` + +Eventually, the [`halmos`](https://github.com/a16z/halmos)-based symbolic tests for the [`erc20`](./src/snekmate/tokens/erc20.vy), [`erc721`](./src/snekmate/tokens/erc721.vy), [`erc1155`](./src/snekmate/tokens/erc1155.vy), and [`math`](./src/snekmate/utils/math.vy) contracts are available in the [`test/tokens/halmos/`](./test/tokens/halmos) and [`test/utils/halmos/`](./test/utils/halmos) directories. You can run the tests by invoking: + +> [!IMPORTANT] +> You must install the [Yices 2 SMT solver](https://github.com/SRI-CSL/yices2) before invoking the [`halmos`](https://github.com/a16z/halmos)-based symbolic tests. + +```console +# Run Halmos ERC-20 symbolic tests. +~$ FOUNDRY_PROFILE=halmos halmos --contract ERC20TestHalmos --config test/halmos.toml + +# Run Halmos ERC-721 symbolic tests. Be careful, this is a very time-consuming operation. +~$ FOUNDRY_PROFILE=halmos halmos --contract ERC721TestHalmos --config test/halmos.toml + +# Run Halmos ERC-1155 symbolic tests. Be careful, this is a very time-consuming operation. +~$ FOUNDRY_PROFILE=halmos halmos --contract ERC1155TestHalmos --config test/halmos.toml + +# Run Halmos math symbolic tests. +~$ FOUNDRY_PROFILE=halmos halmos --contract MathTestHalmos --config test/halmos.toml +``` + +> [!TIP] +> If you encounter any issues, please ensure that you have the [latest](https://github.com/vyperlang/vyper/releases) 🐍Vyper version installed locally. + ## 🙏🏼 Acknowledgements This repository is inspired by or directly modified from many sources, primarily: @@ -150,8 +223,8 @@ This repository is inspired by or directly modified from many sources, primarily - [Disperse Research](https://github.com/banteg/disperse-research) - [Multicall](https://github.com/mds1/multicall) - [OpenZeppelin Contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) -- [solady](https://github.com/Vectorized/solady) -- [solmate](https://github.com/transmissions11/solmate) +- [Solady](https://github.com/Vectorized/solady) +- [Solmate](https://github.com/transmissions11/solmate) ## 🫡 Contributing diff --git a/ape-config.yaml b/ape-config.yaml index 793d4989..da1e2cc6 100644 --- a/ape-config.yaml +++ b/ape-config.yaml @@ -1,7 +1,7 @@ name: snekmate -contracts_folder: src +contracts_folder: src/snekmate default_ecosystem: ethereum plugins: - name: vyper vyper: - evm_version: shanghai + evm_version: cancun diff --git a/eslint.config.js b/eslint.config.js index def7d94d..44d1d9c1 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -19,10 +19,15 @@ module.exports = [ "lib/solmate/**", "lib/prb-test/**", "lib/forge-std/**", + "lib/properties/**", "lib/create-util/**", "lib/erc4626-tests/**", + "lib/FreshCryptoLib/**", + "lib/halmos-cheatcodes/**", "lib/solidity-bytes-utils/**", "lib/openzeppelin-contracts/**", + "echidna-corpus/**", + "crytic-export/**", "cache/**", "out/**", "dist/**", diff --git a/foundry.toml b/foundry.toml index c2090017..fb183373 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,23 +1,37 @@ -## defaults for all profiles +# Defaults for all profiles. [profile.default] -src = 'src' # the source directory -test = 'test' # the test directory -out = 'out' # the output directory (for artifacts) -libs = ['lib'] # a list of library directories -cache = true # whether to cache builds or not -cache_path = 'cache' # where the cache is stored if enabled -force = false # whether to ignore the cache (clean build) -fuzz = { runs = 256 } # the number of fuzz runs for tests -invariant = { runs = 256, depth = 15 } # the number of runs that must execute for each invariant test group -ffi = true # whether to enable foreign function interface (ffi) cheatcodes or not -verbosity = 3 # the verbosity of tests -fs_permissions = [{ access = "read-write", path = "./"}] # set read-write access to project root -solc_version = '0.8.25' # override for the solc version -evm_version = 'shanghai' # set the EVM target version +src = "test" # Set the source directory. +test = "test" # Set the test directory. +out = "out" # Set the output directory for the artifacts. +libs = ["lib"] # Configure an array of library directories. +cache = true # Enable caching. +cache_path = "cache" # Set the path to the cache. +force = false # Do not ignore the cache. +solc_version = "0.8.26" # Set the Solidity compiler version. +evm_version = "cancun" # Set the EVM target version. +optimizer = true # Enable the Solidity compiler optimiser. +optimizer_runs = 200 # Configure the number of optimiser runs. +via_ir = false # Prevent the compilation pipeline from running through the Yul intermediate representation. +verbosity = 3 # Set the verbosity level for the tests. +ffi = true # Enable the foreign function interface (ffi) cheatcode. +no_match_path = "test/**/{echidna,halmos}/**/*" # Run only tests in the test directory that do not match the specified glob pattern. +fs_permissions = [{ access = "read-write", path = "./" }] # Configure read-write access to the project root. +fuzz = { runs = 256, max_test_rejects = 65_536 } # Configure the number of fuzz runs and maximum number of combined inputs that may be rejected for the tests. +invariant = { runs = 256, depth = 15 } # Configure the number of runs and calls (executed in one run) for each invariant test group. -## default overrides for the CI runs +# Default overrides for the CI runs. [profile.ci] -force = true # always perform a clean build -fuzz = { runs = 10_000, max_test_rejects = 350_000 } # increase the number of fuzz runs and maximum number of combined inputs that may be rejected for the tests -invariant = { runs = 375, depth = 500 } # increase the number of runs that must execute for each invariant test group -verbosity = 4 # increase the verbosity of tests +force = true # Perform always a clean build. +verbosity = 4 # Increase the verbosity level for the tests. +fuzz = { runs = 10_000, max_test_rejects = 350_000 } # Increase the number of fuzz runs and maximum number of combined inputs that may be rejected for the tests. +invariant = { runs = 375, depth = 500 } # Increase the number of runs (while preserving the default depth) for each invariant test group. + +# Default overrides for the Echidna tests. +[profile.echidna] +force = true # Perform always a clean build. +evm_version = "shanghai" # Set the EVM target version to `shanghai`. + +# Default overrides for the Halmos tests. +[profile.halmos] +force = true # Perform always a clean build. +evm_version = "shanghai" # Set the EVM target version to `shanghai`. diff --git a/lib/FreshCryptoLib b/lib/FreshCryptoLib new file mode 160000 index 00000000..fd2a0e6e --- /dev/null +++ b/lib/FreshCryptoLib @@ -0,0 +1 @@ +Subproject commit fd2a0e6e64609ade0b0c165e4d66de8106a70db6 diff --git a/lib/halmos-cheatcodes b/lib/halmos-cheatcodes new file mode 160000 index 00000000..c0d86550 --- /dev/null +++ b/lib/halmos-cheatcodes @@ -0,0 +1 @@ +Subproject commit c0d865508c0fee0a11b97732c5e90f9cad6b65a5 diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 06449fe7..337bfd5e 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 06449fe7bcfaafe43abdfc2b28fb6bb189e6ade5 +Subproject commit 337bfd5ea4df9f7ebc755cd3cb4ecb3bd3d33fc7 diff --git a/lib/properties b/lib/properties new file mode 160000 index 00000000..f1ff61b8 --- /dev/null +++ b/lib/properties @@ -0,0 +1 @@ +Subproject commit f1ff61b8e90ce0c9ab138dfe23e80a8afa7f5e37 diff --git a/lib/solady b/lib/solady index ab266e93..cfb1568e 160000 --- a/lib/solady +++ b/lib/solady @@ -1 +1 @@ -Subproject commit ab266e9340671c56fbd102629036f8afc5f9c9de +Subproject commit cfb1568e5171c392a6d1150af26c8375b3d91831 diff --git a/lib/utils/VyperDeployer.sol b/lib/utils/VyperDeployer.sol index 80671693..c8063c13 100644 --- a/lib/utils/VyperDeployer.sol +++ b/lib/utils/VyperDeployer.sol @@ -1,7 +1,14 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Create} from "create-util/Create.sol"; +import {console, StdStyle} from "forge-std/Test.sol"; + +/** + * @dev Error that occurs when compiling a contract has failed. + * @param emitter The contract that emits the error. + */ +error CompilationFailed(address emitter); /** * @dev Error that occurs when deploying a contract has failed. @@ -27,8 +34,8 @@ interface _CheatCodes { * https://github.com/0xKitsune/Foundry-Vyper/blob/main/lib/utils/VyperDeployer.sol. * @dev The Vyper Contract Deployer is a pre-built contract containing functions that * use a path, a filename, any ABI-encoded constructor arguments, and optionally the - * target EVM version, and deploy the corresponding Vyper contract, returning the address - * that the bytecode was deployed to. + * target EVM version and the compiler optimisation mode, and deploy the corresponding + * Vyper contract, returning the address that the bytecode was deployed to. */ contract VyperDeployer is Create { address private constant HEVM_ADDRESS = @@ -58,15 +65,30 @@ contract VyperDeployer is Create { * @dev Create a list of strings with the commands necessary * to compile Vyper contracts. */ - string[] memory cmds = new string[](2); - cmds[0] = "vyper"; - cmds[1] = string.concat(path, fileName, ".vy"); + string[] memory cmds = new string[](3); + cmds[0] = "python"; + cmds[1] = "lib/utils/compile.py"; + cmds[2] = string.concat(path, fileName, ".vy"); /** * @dev Compile the Vyper contract and return the bytecode. */ bytes memory bytecode = cheatCodes.ffi(cmds); + /** + * @dev Revert if the Vyper compilation failed or is a zero-length + * contract creation bytecode. + */ + if (bytecode.length == 0) { + // solhint-disable-next-line no-console + console.log( + StdStyle.red( + "Vyper compilation failed! Please ensure that you have a valid Vyper version installed." + ) + ); + revert CompilationFailed({emitter: self}); + } + /** * @dev Deploy the bytecode with the `CREATE` instruction. */ @@ -101,15 +123,30 @@ contract VyperDeployer is Create { * @dev Create a list of strings with the commands necessary * to compile Vyper contracts. */ - string[] memory cmds = new string[](2); - cmds[0] = "vyper"; - cmds[1] = string.concat(path, fileName, ".vy"); + string[] memory cmds = new string[](3); + cmds[0] = "python"; + cmds[1] = "lib/utils/compile.py"; + cmds[2] = string.concat(path, fileName, ".vy"); /** * @dev Compile the Vyper contract and return the bytecode. */ bytes memory bytecode = cheatCodes.ffi(cmds); + /** + * @dev Revert if the Vyper compilation failed or is a zero-length + * contract creation bytecode. + */ + if (bytecode.length == 0) { + // solhint-disable-next-line no-console + console.log( + StdStyle.red( + "Vyper compilation failed! Please ensure that you have a valid Vyper version installed." + ) + ); + revert CompilationFailed({emitter: self}); + } + /** * @dev Add the ABI-encoded constructor arguments to the * deployment bytecode. @@ -132,37 +169,57 @@ contract VyperDeployer is Create { * @dev Compiles a Vyper contract and returns the address that the contract * was deployed to. If the deployment fails, an error is thrown. * @notice Function overload of `deployContract` that allows the configuration - * of the target EVM version. + * of the target EVM version and the compiler optimisation mode. * @param path The directory path of the Vyper contract. * For example, the path of "utils" is "src/utils/". * @param fileName The file name of the Vyper contract. * For example, the file name for "ECDSA.vy" is "ECDSA". * @param evmVersion The EVM version used for compilation. - * For example, the EVM version for the Paris hard fork is "paris". + * For example, the EVM version for the Cancun-Deneb hard fork is "cancun". * You can retrieve all available Vyper EVM versions by invoking `vyper -h`. + * @param optimiserMode The optimisation mode used for compilation. + * For example, the default optimisation mode since Vyper `0.3.10` is "gas". + * You can retrieve all available Vyper optimisation modes by invoking `vyper -h`. * @return deployedAddress The address that the contract was deployed to. */ function deployContract( string calldata path, string calldata fileName, string calldata evmVersion, - bool /*overloadPlaceholder*/ + string calldata optimiserMode ) public returns (address deployedAddress) { /** * @dev Create a list of strings with the commands necessary * to compile Vyper contracts. */ - string[] memory cmds = new string[](4); - cmds[0] = "vyper"; - cmds[1] = string.concat(path, fileName, ".vy"); - cmds[2] = "--evm-version"; - cmds[3] = evmVersion; + string[] memory cmds = new string[](7); + cmds[0] = "python"; + cmds[1] = "lib/utils/compile.py"; + cmds[2] = string.concat(path, fileName, ".vy"); + cmds[3] = "--evm-version"; + cmds[4] = evmVersion; + cmds[5] = "--optimize"; + cmds[6] = optimiserMode; /** * @dev Compile the Vyper contract and return the bytecode. */ bytes memory bytecode = cheatCodes.ffi(cmds); + /** + * @dev Revert if the Vyper compilation failed or is a zero-length + * contract creation bytecode. + */ + if (bytecode.length == 0) { + // solhint-disable-next-line no-console + console.log( + StdStyle.red( + "Vyper compilation failed! Please ensure that you have a valid Vyper version installed." + ) + ); + revert CompilationFailed({emitter: self}); + } + /** * @dev Deploy the bytecode with the `CREATE` instruction. */ @@ -181,15 +238,18 @@ contract VyperDeployer is Create { * is thrown. * @notice Function overload of `deployContract`, which allows the passing of * any ABI-encoded constructor arguments and enables the configuration of the - * target EVM version. + * target EVM version and the compiler optimisation mode. * @param path The directory path of the Vyper contract. * For example, the path of "utils" is "src/utils/". * @param fileName The file name of the Vyper contract. * For example, the file name for "ECDSA.vy" is "ECDSA". * @param args The ABI-encoded constructor arguments. * @param evmVersion The EVM version used for compilation. - * For example, the EVM version for the Paris hard fork is "paris". + * For example, the EVM version for the Cancun-Deneb hard fork is "cancun". * You can retrieve all available Vyper EVM versions by invoking `vyper -h`. + * @param optimiserMode The optimisation mode used for compilation. + * For example, the default optimisation mode since Vyper `0.3.10` is "gas". + * You can retrieve all available Vyper optimisation modes by invoking `vyper -h`. * @return deployedAddress The address that the contract was deployed to. */ function deployContract( @@ -197,23 +257,40 @@ contract VyperDeployer is Create { string calldata fileName, bytes calldata args, string calldata evmVersion, - bool /*overloadPlaceholder*/ + string calldata optimiserMode ) public returns (address deployedAddress) { /** * @dev Create a list of strings with the commands necessary * to compile Vyper contracts. */ - string[] memory cmds = new string[](4); - cmds[0] = "vyper"; - cmds[1] = string.concat(path, fileName, ".vy"); - cmds[2] = "--evm-version"; - cmds[3] = evmVersion; + string[] memory cmds = new string[](7); + cmds[0] = "python"; + cmds[1] = "lib/utils/compile.py"; + cmds[2] = string.concat(path, fileName, ".vy"); + cmds[3] = "--evm-version"; + cmds[4] = evmVersion; + cmds[5] = "--optimize"; + cmds[6] = optimiserMode; /** * @dev Compile the Vyper contract and return the bytecode. */ bytes memory bytecode = cheatCodes.ffi(cmds); + /** + * @dev Revert if the Vyper compilation failed or is a zero-length + * contract creation bytecode. + */ + if (bytecode.length == 0) { + // solhint-disable-next-line no-console + console.log( + StdStyle.red( + "Vyper compilation failed! Please ensure that you have a valid Vyper version installed." + ) + ); + revert CompilationFailed({emitter: self}); + } + /** * @dev Add the ABI-encoded constructor arguments to the * deployment bytecode. diff --git a/lib/utils/compile.py b/lib/utils/compile.py new file mode 100644 index 00000000..409fe084 --- /dev/null +++ b/lib/utils/compile.py @@ -0,0 +1,9 @@ +import sys, subprocess + +result = subprocess.run(["vyper"] + sys.argv[1:], capture_output=True, text=True) +if result.returncode != 0: + raise Exception("Error compiling: " + sys.argv[1]) + +# Remove any leading and trailing whitespace characters +# from the compilation result. +sys.stdout.write(result.stdout.strip()) diff --git a/package.json b/package.json index af8e671a..36516a30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "snekmate", - "version": "0.0.5", + "version": "0.1.0-rc.1", "description": "State-of-the-art, highly opinionated, hyper-optimised, and secure 🐍Vyper smart contract building blocks.", "author": "Pascal Marco Caversaccio ", "license": "AGPL-3.0-only", @@ -30,7 +30,8 @@ "lint:fix": "pnpm prettier:fix && pnpm solhint:fix && npx eslint . --fix" }, "files": [ - "src/snekmate/**/*.vy", + "src/snekmate/**/*.{vy,vyi}", + "!src/snekmate/**/mocks/**/*.{vy,vyi}", "LICENSE", "README.md", "CHANGELOG.md" diff --git a/pyproject.toml b/pyproject.toml index cd8eb970..49faf6ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,16 +1,24 @@ [project] name = "snekmate" -version = "0.0.5" +version = "0.1.0rc1" description = "State-of-the-art, highly opinionated, hyper-optimised, and secure 🐍Vyper smart contract building blocks." -readme = {file = "README.md", content-type = "text/markdown"} +readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.10" -license = {text = "AGPL-3.0-only License"} -keywords = ["security", "library", "ethereum", "smart-contracts", "evm", "vyper", "vyper-contracts"] +license = { text = "AGPL-3.0-only License" } +keywords = [ + "security", + "library", + "ethereum", + "smart-contracts", + "evm", + "vyper", + "vyper-contracts", +] authors = [ - {name = "Pascal Marco Caversaccio", email = "pascal.caversaccio@hotmail.ch"}, + { name = "Pascal Marco Caversaccio", email = "pascal.caversaccio@hotmail.ch" }, ] maintainers = [ - {name = "Pascal Marco Caversaccio", email = "pascal.caversaccio@hotmail.ch"}, + { name = "Pascal Marco Caversaccio", email = "pascal.caversaccio@hotmail.ch" }, ] classifiers = [ "Development Status :: 5 - Production/Stable", diff --git a/remappings.txt b/remappings.txt index 9b6bb5c2..1bbd5456 100644 --- a/remappings.txt +++ b/remappings.txt @@ -5,6 +5,9 @@ solmate/=lib/solmate/src/ prb/test/=lib/prb-test/src/ forge-std/=lib/forge-std/src/ erc4626-tests/=lib/erc4626-tests/ +properties/=lib/properties/contracts/ create-util/=lib/create-util/contracts/ +halmos-cheatcodes/=lib/halmos-cheatcodes/src/ +fresh-crypto-lib=lib/FreshCryptoLib/solidity/src/ openzeppelin/=lib/openzeppelin-contracts/contracts/ solidity-bytes-utils/=lib/solidity-bytes-utils/contracts/ diff --git a/scripts/compile.py b/scripts/compile.py deleted file mode 100644 index 3f25ed33..00000000 --- a/scripts/compile.py +++ /dev/null @@ -1,9 +0,0 @@ -import subprocess, glob - -for filename in glob.glob("src/**/*.vy", recursive=True): - result = subprocess.run( - ["vyper", "-f", "userdoc,devdoc", filename], capture_output=True, text=True - ) - if result.stderr != "": - raise Exception("Error compiling: " + filename) - print("stdout:", result.stdout) diff --git a/src/snekmate/auth/AccessControl.vy b/src/snekmate/auth/access_control.vy similarity index 74% rename from src/snekmate/auth/AccessControl.vy rename to src/snekmate/auth/access_control.vy index e4a5b14f..754ca755 100644 --- a/src/snekmate/auth/AccessControl.vy +++ b/src/snekmate/auth/access_control.vy @@ -1,14 +1,14 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Multi-Role-Based Access Control Functions -@custom:contract-name AccessControl +@custom:contract-name access_control @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions can be used to implement role-based access control mechanisms. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and - be unique. The best way to achieve this is by using `public - constant` hash digests: + be unique. The best way to achieve this is by using `public` + `constant` hash digests: ```vy MY_ROLE: public(constant(bytes32)) = keccak256("MY_ROLE"); ``` @@ -19,16 +19,29 @@ parsing error, no `@` character is added to the visibility decorator `@external` in the following examples; please add them accordingly): ```vy + from ethereum.ercs import IERC165 + implements: IERC165 + + from snekmate.auth.interfaces import IAccessControl + implements: IAccessControl + + from snekmate.auth import access_control + initializes: access_control + + exports: access_control.__interface__ + + ... + external def foo(): - assert self.hasRole[MY_ROLE][msg.sender], "AccessControl: account is missing role" + assert access_control.hasRole[MY_ROLE][msg.sender], "access_control: account is missing role" ... OR external def foo(): - self._check_role(MY_ROLE, msg.sender) + access_control._check_role(MY_ROLE, msg.sender) ... ``` @@ -49,10 +62,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 # @dev We import and implement the `IAccessControl` @@ -69,22 +82,6 @@ implements: IAccessControl DEFAULT_ADMIN_ROLE: public(constant(bytes32)) = empty(bytes32) -# @dev An additional 32-byte access role. -# @notice Please adjust the naming of the variable -# according to your specific requirement, -# e.g. `MINTER_ROLE`. -ADDITIONAL_ROLE_1: public(constant(bytes32)) = keccak256("ADDITIONAL_ROLE_1") - - -# @dev An additional 32-byte access role. -# @notice Please adjust the naming of the variable -# according to your specific requirement, -# e.g. `PAUSER_ROLE`. Also, feel free to add more -# roles if necessary. In this case, it is important -# to extend the constructor accordingly. -ADDITIONAL_ROLE_2: public(constant(bytes32)) = keccak256("ADDITIONAL_ROLE_2") - - # @dev Stores the ERC-165 interface identifier for each # imported interface. The ERC-165 interface identifier # is defined as the XOR of all function selectors in the @@ -103,52 +100,17 @@ hasRole: public(HashMap[bytes32, HashMap[address, bool]]) getRoleAdmin: public(HashMap[bytes32, bytes32]) -# @dev Emitted when `new_admin_role` is set as -# `role`'s admin role, replacing `previous_admin_role`. -# Note that `DEFAULT_ADMIN_ROLE` is the starting -# admin for all roles, despite `RoleAdminChanged` -# not being emitted signaling this. -event RoleAdminChanged: - role: indexed(bytes32) - previous_admin_role: indexed(bytes32) - new_admin_role: indexed(bytes32) - - -# @dev Emitted when `account` is granted `role`. -# Note that `sender` is the account (an admin -# role bearer) that originated the contract call. -event RoleGranted: - role: indexed(bytes32) - account: indexed(address) - sender: indexed(address) - - -# @dev Emitted when `account` is revoked `role`. -# Note that `sender` is the account that originated -# the contract call: -# - if using `revokeRole`, it is the admin role -# bearer, -# - if using `renounceRole`, it is the role bearer -# (i.e. `account`). -event RoleRevoked: - role: indexed(bytes32) - account: indexed(address) - sender: indexed(address) - - -@external +@deploy @payable def __init__(): """ @dev To omit the opcodes for checking the `msg.value` in the creation-time EVM bytecode, the constructor is declared as `payable`. - @notice All predefined roles will be assigned to - the `msg.sender`. + @notice The `DEFAULT_ADMIN_ROLE` role will be assigned + to the `msg.sender`. """ self._grant_role(DEFAULT_ADMIN_ROLE, msg.sender) - self._grant_role(ADDITIONAL_ROLE_1, msg.sender) - self._grant_role(ADDITIONAL_ROLE_2, msg.sender) @external @@ -208,7 +170,7 @@ def renounceRole(role: bytes32, account: address): @param role The 32-byte role definition. @param account The 20-byte address of the account. """ - assert account == msg.sender, "AccessControl: can only renounce roles for itself" + assert account == msg.sender, "access_control: can only renounce roles for itself" self._revoke_role(role, account) @@ -234,7 +196,7 @@ def _check_role(role: bytes32, account: address): @param role The 32-byte role definition. @param account The 20-byte address of the account. """ - assert self.hasRole[role][account], "AccessControl: account is missing role" + assert self.hasRole[role][account], "access_control: account is missing role" @internal @@ -248,7 +210,7 @@ def _set_role_admin(role: bytes32, admin_role: bytes32): """ previous_admin_role: bytes32 = self.getRoleAdmin[role] self.getRoleAdmin[role] = admin_role - log RoleAdminChanged(role, previous_admin_role, admin_role) + log IAccessControl.RoleAdminChanged(role, previous_admin_role, admin_role) @internal @@ -262,7 +224,7 @@ def _grant_role(role: bytes32, account: address): """ if (not(self.hasRole[role][account])): self.hasRole[role][account] = True - log RoleGranted(role, account, msg.sender) + log IAccessControl.RoleGranted(role, account, msg.sender) @internal @@ -276,4 +238,4 @@ def _revoke_role(role: bytes32, account: address): """ if (self.hasRole[role][account]): self.hasRole[role][account] = False - log RoleRevoked(role, account, msg.sender) + log IAccessControl.RoleRevoked(role, account, msg.sender) diff --git a/src/snekmate/auth/interfaces/IAccessControl.vy b/src/snekmate/auth/interfaces/IAccessControl.vyi similarity index 93% rename from src/snekmate/auth/interfaces/IAccessControl.vy rename to src/snekmate/auth/interfaces/IAccessControl.vyi index 801e132d..3b067a82 100644 --- a/src/snekmate/auth/interfaces/IAccessControl.vy +++ b/src/snekmate/auth/interfaces/IAccessControl.vyi @@ -1,10 +1,10 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ -@title AccessControl Interface Definition +@title `access_control` Interface Definition @custom:contract-name IAccessControl @license GNU Affero General Public License v3.0 only @author pcaversaccio -@notice The interface definition of `AccessControl` +@notice The interface definition of `access_control` to support the ERC-165 detection. In order to ensure consistency and interoperability, we follow OpenZeppelin's definition here: @@ -59,7 +59,7 @@ def hasRole(role: bytes32, account: address) -> bool: @return bool The verification whether the role `role` has been granted to `account` or not. """ - return empty(bool) + return ... @external @@ -70,12 +70,12 @@ def getRoleAdmin(role: bytes32) -> bytes32: `role`. @notice See `grantRole` and `revokeRole`. To change a role's admin, use - {AccessControl-set_role_admin}. + {access_control-set_role_admin}. @param role The 32-byte role definition. @return bytes32 The 32-byte admin role that controls `role`. """ - return empty(bytes32) + return ... @external @@ -89,7 +89,7 @@ def grantRole(role: bytes32, account: address): @param role The 32-byte role definition. @param account The 20-byte address of the account. """ - pass + ... @external @@ -102,7 +102,7 @@ def revokeRole(role: bytes32, account: address): @param role The 32-byte role definition. @param account The 20-byte address of the account. """ - pass + ... @external @@ -120,4 +120,4 @@ def renounceRole(role: bytes32, account: address): @param role The 32-byte role definition. @param account The 20-byte address of the account. """ - pass + ... diff --git a/src/snekmate/auth/mocks/access_control_mock.vy b/src/snekmate/auth/mocks/access_control_mock.vy new file mode 100644 index 00000000..8292f8b3 --- /dev/null +++ b/src/snekmate/auth/mocks/access_control_mock.vy @@ -0,0 +1,68 @@ +# pragma version ~=0.4.0rc6 +""" +@title `access_control` Module Reference Implementation +@custom:contract-name access_control_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and implement the `IERC165` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC165 +implements: IERC165 + + +# @dev We import and implement the `IAccessControl` +# interface, which is written using standard Vyper +# syntax. +from ..interfaces import IAccessControl +implements: IAccessControl + + +# @dev We import and initialise the `access_control` module. +from .. import access_control as ac +initializes: ac + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `access_control` module. The built-in dunder method +# `__interface__` allows you to export all functions of a +# module without specifying the individual functions (see +# https://github.com/vyperlang/vyper/pull/3919). Please take +# note that if you do not know the full interface of a module +# contract, you can get the `.vyi` interface in Vyper by using +# `vyper -f interface your_filename.vy` or the external interface +# by using `vyper -f external_interface your_filename.vy`. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ac.__interface__ + + +# @dev The 32-byte minter role. +MINTER_ROLE: public(constant(bytes32)) = keccak256("MINTER_ROLE") + + +# @dev The 32-byte pauser role. +PAUSER_ROLE: public(constant(bytes32)) = keccak256("PAUSER_ROLE") + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @notice All predefined roles will be assigned to + the `msg.sender`. + """ + # The following line assigns the `DEFAULT_ADMIN_ROLE` + # to the `msg.sender`. + ac.__init__() + ac._grant_role(MINTER_ROLE, msg.sender) + ac._grant_role(PAUSER_ROLE, msg.sender) diff --git a/src/snekmate/auth/mocks/ownable_2step_mock.vy b/src/snekmate/auth/mocks/ownable_2step_mock.vy new file mode 100644 index 00000000..de6f2e76 --- /dev/null +++ b/src/snekmate/auth/mocks/ownable_2step_mock.vy @@ -0,0 +1,51 @@ +# pragma version ~=0.4.0rc6 +""" +@title `ownable_2step` Module Reference Implementation +@custom:contract-name ownable_2step_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and initialise the `ownable` module. +from .. import ownable as ow +initializes: ow + + +# @dev We import and initialise the `ownable_2step` module. +from .. import ownable_2step as o2 +initializes: o2[ownable := ow] + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `ownable_2step` module. The built-in dunder method +# `__interface__` allows you to export all functions of a +# module without specifying the individual functions (see +# https://github.com/vyperlang/vyper/pull/3919). Please take +# note that if you do not know the full interface of a module +# contract, you can get the `.vyi` interface in Vyper by using +# `vyper -f interface your_filename.vy` or the external interface +# by using `vyper -f external_interface your_filename.vy`. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: o2.__interface__ + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @notice The `owner` role will be assigned to + the `msg.sender`. + """ + # The following line assigns the `owner` + # to the `msg.sender`. + ow.__init__() + o2.__init__() diff --git a/src/snekmate/auth/mocks/ownable_mock.vy b/src/snekmate/auth/mocks/ownable_mock.vy new file mode 100644 index 00000000..a0f2e5e2 --- /dev/null +++ b/src/snekmate/auth/mocks/ownable_mock.vy @@ -0,0 +1,45 @@ +# pragma version ~=0.4.0rc6 +""" +@title `ownable` Module Reference Implementation +@custom:contract-name ownable_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and initialise the `ownable` module. +from .. import ownable as ow +initializes: ow + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `ownable` module. The built-in dunder method +# `__interface__` allows you to export all functions of a +# module without specifying the individual functions (see +# https://github.com/vyperlang/vyper/pull/3919). Please take +# note that if you do not know the full interface of a module +# contract, you can get the `.vyi` interface in Vyper by using +# `vyper -f interface your_filename.vy` or the external interface +# by using `vyper -f external_interface your_filename.vy`. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ow.__interface__ + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @notice The `owner` role will be assigned to + the `msg.sender`. + """ + # The following line assigns the `owner` + # to the `msg.sender`. + ow.__init__() diff --git a/src/snekmate/auth/Ownable.vy b/src/snekmate/auth/ownable.vy similarity index 93% rename from src/snekmate/auth/Ownable.vy rename to src/snekmate/auth/ownable.vy index a8ddff20..35c05a21 100644 --- a/src/snekmate/auth/Ownable.vy +++ b/src/snekmate/auth/ownable.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Owner-Based Access Control Functions -@custom:contract-name Ownable +@custom:contract-name ownable @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions can be used to implement a basic access @@ -30,7 +30,7 @@ event OwnershipTransferred: new_owner: indexed(address) -@external +@deploy @payable def __init__(): """ @@ -54,7 +54,7 @@ def transfer_ownership(new_owner: address): @param new_owner The 20-byte address of the new owner. """ self._check_owner() - assert new_owner != empty(address), "Ownable: new owner is the zero address" + assert new_owner != empty(address), "ownable: new owner is the zero address" self._transfer_ownership(new_owner) @@ -76,7 +76,7 @@ def _check_owner(): """ @dev Throws if the sender is not the owner. """ - assert msg.sender == self.owner, "Ownable: caller is not the owner" + assert msg.sender == self.owner, "ownable: caller is not the owner" @internal diff --git a/src/snekmate/auth/Ownable2Step.vy b/src/snekmate/auth/ownable_2step.vy similarity index 57% rename from src/snekmate/auth/Ownable2Step.vy rename to src/snekmate/auth/ownable_2step.vy index d4aa02c5..178172e3 100644 --- a/src/snekmate/auth/Ownable2Step.vy +++ b/src/snekmate/auth/ownable_2step.vy @@ -1,28 +1,45 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title 2-Step Ownership Transfer Functions -@custom:contract-name Ownable2Step +@custom:contract-name ownable_2step @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions can be used to implement a basic access control mechanism, where there is an account (an owner) that can be granted exclusive access to specific functions. - By default, the owner account will be the one that deploys - the contract. This can later be changed with `transfer_ownership` - and `accept_ownership`. + This extension to the {ownable} contract includes a two-step + ownership transfer mechanism where the new owner must call + `accept_ownership` to replace the old one. This can help + avoid common mistakes, such as ownership transfers to incorrect + accounts or to contracts that are unable to interact with + the permission system. By default, the owner account will + be the one that deploys the contract. This can later be + changed with `transfer_ownership` and `accept_ownership`. The implementation is inspired by OpenZeppelin's implementation here: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable2Step.sol. """ -# @dev Returns the address of the current owner. -# @notice If you declare a variable as `public`, -# Vyper automatically generates an `external` -# getter function for the variable. -owner: public(address) +# @dev We import and use the `ownable` module. +from . import ownable +uses: ownable + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) the `external` getter +# function `owner` from the `ownable` module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ownable.owner # @dev Returns the address of the pending owner. +# @notice If you declare a variable as `public`, +# Vyper automatically generates an `external` +# getter function for the variable. pending_owner: public(address) @@ -33,24 +50,19 @@ event OwnershipTransferStarted: new_owner: indexed(address) -# @dev Emitted when the ownership is transferred -# from `previous_owner` to `new_owner`. -event OwnershipTransferred: - previous_owner: indexed(address) - new_owner: indexed(address) - - -@external +@deploy @payable def __init__(): """ @dev To omit the opcodes for checking the `msg.value` in the creation-time EVM bytecode, the constructor is declared as `payable`. - @notice The `owner` role will be assigned to - the `msg.sender`. + @notice At initialisation time, the `owner` role will + be assigned to the `msg.sender` since we `uses` + the `ownable` module, which implements the + aforementioned logic at contract creation time. """ - self._transfer_ownership(msg.sender) + pass @external @@ -68,9 +80,9 @@ def transfer_ownership(new_owner: address): there is one. @param new_owner The 20-byte address of the new owner. """ - self._check_owner() + ownable._check_owner() self.pending_owner = new_owner - log OwnershipTransferStarted(self.owner, new_owner) + log OwnershipTransferStarted(ownable.owner, new_owner) @external @@ -80,29 +92,23 @@ def accept_ownership(): @notice Note that this function can only be called by the current `pending_owner`. """ - assert self.pending_owner == msg.sender, "Ownable2Step: caller is not the new owner" + assert self.pending_owner == msg.sender, "ownable_2step: caller is not the new owner" self._transfer_ownership(msg.sender) @external def renounce_ownership(): """ - @dev Sourced from {Ownable-renounce_ownership}. - @notice See {Ownable-renounce_ownership} for - the function docstring. + @dev Leaves the contract without an owner. + @notice Renouncing ownership will leave the + contract without an owner, thereby + removing any functionality that is + only available to the owner. """ - self._check_owner() + ownable._check_owner() self._transfer_ownership(empty(address)) -@internal -def _check_owner(): - """ - @dev Throws if the sender is not the owner. - """ - assert msg.sender == self.owner, "Ownable2Step: caller is not the owner" - - @internal def _transfer_ownership(new_owner: address): """ @@ -114,6 +120,4 @@ def _transfer_ownership(new_owner: address): @param new_owner The 20-byte address of the new owner. """ self.pending_owner = empty(address) - old_owner: address = self.owner - self.owner = new_owner - log OwnershipTransferred(old_owner, new_owner) + ownable._transfer_ownership(new_owner) diff --git a/src/snekmate/extensions/ERC2981.vy b/src/snekmate/extensions/erc2981.vy similarity index 70% rename from src/snekmate/extensions/ERC2981.vy rename to src/snekmate/extensions/erc2981.vy index 32e6cf65..694ab42e 100644 --- a/src/snekmate/extensions/ERC2981.vy +++ b/src/snekmate/extensions/erc2981.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title ERC-721 and ERC-1155 Compatible ERC-2981 Reference Implementation -@custom:contract-name ERC2981 +@custom:contract-name erc2981 @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice Reference implementation of the non-fungible token (NFT) royalty @@ -24,16 +24,34 @@ The implementation is inspired by OpenZeppelin's implementation here: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol. -@custom:security If you integrate this contract with an ERC-721 contract, please - consider clearing the royalty information from storage on calling - `burn` (to avoid any NatSpec parsing error, no `@` character is added - to the visibility decorator `@internal` in the following example; - please add it accordingly): +@custom:security If you integrate this contract with an ERC-721 contract, you may + want to consider clearing the royalty information from storage on + calling `burn` (to avoid any NatSpec parsing error, no `@` character + is added to the visibility decorators `@external` and `@internal` in + the following example; please add them accordingly): ```vy + from ethereum.ercs import IERC721 + implements: IERC721 + + from snekmate.extensions.interfaces import IERC2981 + implements: IERC2981 + + from snekmate.tokens import erc721 + from snekmate.extensions import erc2981 + + exports: ... + + ... + + external + def burn(token_id: uint256): + assert erc721._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved" + self._burn(token_id) + internal def _burn(token_id: uint256): - ... - self._reset_token_royalty(token_id) + erc721._burn(token_id) + erc2981._reset_token_royalty(token_id) ``` Due to the fungibility of ERC-1155 tokens, the implementation of @@ -41,10 +59,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 # @dev We import and implement the `IERC2981` interface, @@ -53,6 +71,36 @@ import interfaces.IERC2981 as IERC2981 implements: IERC2981 +# @dev We import and use the `ownable` module. +from ..auth import ownable +uses: ownable + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `ownable` module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ( + ownable.owner, + # @notice If you integrate the function `transfer_ownership` + # into an ERC-721 or ERC-1155 contract that implements an + # `is_minter` role, ensure that the previous owner's minter + # role is also removed and the minter role is assigned to the + # `new_owner` accordingly. + ownable.transfer_ownership, + # @notice If you integrate the function `renounce_ownership` + # into an ERC-721 or ERC-1155 contract that implements an + # `is_minter` role, ensure that the previous owner's minter + # role as well as all non-owner minter addresses are also + # removed before calling `renounce_ownership`. + ownable.renounce_ownership, +) + + # @dev Stores the ERC-165 interface identifier for each # imported interface. The ERC-165 interface identifier # is defined as the XOR of all function selectors in the @@ -66,13 +114,6 @@ _SUPPORTED_INTERFACES: constant(bytes4[2]) = [ ] -# @dev Returns the address of the current owner. -# @notice If you declare a variable as `public`, -# Vyper automatically generates an `external` -# getter function for the variable. -owner: public(address) - - # @dev Tightly packed royalty information struct. Note that # Vyper does not currently support tight packing, but will # do so in the near future. @@ -96,14 +137,7 @@ _token_royalty_info: HashMap[uint256, RoyaltyInfo] _fee_denominator: uint256 -# @dev Emitted when the ownership is transferred -# from `previous_owner` to `new_owner`. -event OwnershipTransferred: - previous_owner: indexed(address) - new_owner: indexed(address) - - -@external +@deploy @payable def __init__(): """ @@ -112,18 +146,19 @@ def __init__(): is declared as `payable`. @notice We set the default value of `_fee_denominator` to `10_000` so that the fee is in basis points by - default. Also, the `owner` role will be assigned - to the `msg.sender`. + default. At initialisation time, the `owner` role + will be assigned to the `msg.sender` since we `uses` + the `ownable` module, which implements the + aforementioned logic at contract creation time. IMPORTANT: The `_default_royalty_info` is set to the EVM default values `receiver = empty(address)` and `royalty_fraction = empty(uint96)`. If you want to set your own default values during contract creation, - you can call `self._default_royalty(receiver, fee_numerator)` + you can call `erc2981._default_royalty(receiver, fee_numerator)` in the constructor. """ self._fee_denominator = 10_000 - self._transfer_ownership(msg.sender) @external @@ -161,7 +196,7 @@ def royaltyInfo(token_id: uint256, sale_price: uint256) -> (address, uint256): # The following line uses intentionally checked arithmetic to # prevent a theoretically possible overflow. - royalty_amount: uint256 = (sale_price * convert(royalty.royalty_fraction, uint256)) / self._fee_denominator + royalty_amount: uint256 = (sale_price * convert(royalty.royalty_fraction, uint256)) // self._fee_denominator return (royalty.receiver, royalty_amount) @@ -180,7 +215,7 @@ def set_default_royalty(receiver: address, fee_numerator: uint96): @param fee_numerator The 12-byte fee numerator used to calculate the royalty fraction. """ - self._check_owner() + ownable._check_owner() self._set_default_royalty(receiver, fee_numerator) @@ -190,7 +225,7 @@ def delete_default_royalty(): @dev Removes the default royalty information. This function can only be called by the current `owner`. """ - self._check_owner() + ownable._check_owner() self._delete_default_royalty() @@ -209,7 +244,7 @@ def set_token_royalty(token_id: uint256, receiver: address, fee_numerator: uint9 @param fee_numerator The 12-byte fee numerator used to calculate the royalty fraction. """ - self._check_owner() + ownable._check_owner() self._set_token_royalty(token_id, receiver, fee_numerator) @@ -221,45 +256,10 @@ def reset_token_royalty(token_id: uint256): the current `owner`. @param token_id The 32-byte identifier of the token. """ - self._check_owner() + ownable._check_owner() self._reset_token_royalty(token_id) -@external -def transfer_ownership(new_owner: address): - """ - @dev Sourced from {Ownable-transfer_ownership}. - @notice See {Ownable-transfer_ownership} for - the function docstring. - @custom:security If you integrate this implementation into an - ERC-721 or ERC-1155 contract that implements - an `is_minter` role, ensure that the previous - owner's minter role is also removed and the - minter role is assigned to the `new_owner` - accordingly. - """ - self._check_owner() - assert new_owner != empty(address), "Ownable: new owner is the zero address" - self._transfer_ownership(new_owner) - - -@external -def renounce_ownership(): - """ - @dev Sourced from {Ownable-renounce_ownership}. - @notice See {Ownable-renounce_ownership} for - the function docstring. - @custom:security If you integrate this implementation into an - ERC-721 or ERC-1155 contract that implements - an `is_minter` role, ensure that the previous - owner's minter role as well as all non-owner - minter addresses are also removed before calling - `renounce_ownership`. - """ - self._check_owner() - self._transfer_ownership(empty(address)) - - @internal def _set_default_royalty(receiver: address, fee_numerator: uint96): """ @@ -275,9 +275,9 @@ def _set_default_royalty(receiver: address, fee_numerator: uint96): the royalty fraction. """ denominator: uint256 = self._fee_denominator - assert convert(fee_numerator, uint256) <= denominator, "ERC2981: royalty fee will exceed sale_price" - assert receiver != empty(address), "ERC2981: invalid receiver" - self._default_royalty_info = RoyaltyInfo({receiver: receiver, royalty_fraction: fee_numerator}) + assert convert(fee_numerator, uint256) <= denominator, "erc2981: royalty fee will exceed sale_price" + assert receiver != empty(address), "erc2981: invalid receiver" + self._default_royalty_info = RoyaltyInfo(receiver=receiver, royalty_fraction=fee_numerator) @internal @@ -286,7 +286,7 @@ def _delete_default_royalty(): @dev Removes the default royalty information. @notice This is an `internal` function without access restriction. """ - self._default_royalty_info = RoyaltyInfo({receiver: empty(address), royalty_fraction: empty(uint96)}) + self._default_royalty_info = RoyaltyInfo(receiver=empty(address), royalty_fraction=empty(uint96)) @internal @@ -305,9 +305,9 @@ def _set_token_royalty(token_id: uint256, receiver: address, fee_numerator: uint the royalty fraction. """ denominator: uint256 = self._fee_denominator - assert convert(fee_numerator, uint256) <= denominator, "ERC2981: royalty fee will exceed sale_price" - assert receiver != empty(address), "ERC2981: invalid receiver" - self._token_royalty_info[token_id] = RoyaltyInfo({receiver: receiver, royalty_fraction: fee_numerator}) + assert convert(fee_numerator, uint256) <= denominator, "erc2981: royalty fee will exceed sale_price" + assert receiver != empty(address), "erc2981: invalid receiver" + self._token_royalty_info[token_id] = RoyaltyInfo(receiver=receiver, royalty_fraction=fee_numerator) @internal @@ -318,26 +318,4 @@ def _reset_token_royalty(token_id: uint256): @notice This is an `internal` function without access restriction. @param token_id The 32-byte identifier of the token. """ - self._token_royalty_info[token_id] = RoyaltyInfo({receiver: empty(address), royalty_fraction: empty(uint96)}) - - -@internal -def _check_owner(): - """ - @dev Sourced from {Ownable-_check_owner}. - @notice See {Ownable-_check_owner} for - the function docstring. - """ - assert msg.sender == self.owner, "Ownable: caller is not the owner" - - -@internal -def _transfer_ownership(new_owner: address): - """ - @dev Sourced from {Ownable-_transfer_ownership}. - @notice See {Ownable-_transfer_ownership} for - the function docstring. - """ - old_owner: address = self.owner - self.owner = new_owner - log OwnershipTransferred(old_owner, new_owner) + self._token_royalty_info[token_id] = RoyaltyInfo(receiver=empty(address), royalty_fraction=empty(uint96)) diff --git a/src/snekmate/extensions/ERC4626.vy b/src/snekmate/extensions/erc4626.vy similarity index 55% rename from src/snekmate/extensions/ERC4626.vy rename to src/snekmate/extensions/erc4626.vy index 257d2601..099fc05c 100644 --- a/src/snekmate/extensions/ERC4626.vy +++ b/src/snekmate/extensions/erc4626.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Modern and Gas-Efficient ERC-4626 Tokenised Vault Implementation -@custom:contract-name ERC4626 +@custom:contract-name erc4626 @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions implement the ERC-4626 @@ -50,16 +50,16 @@ """ -# @dev We import and implement the `ERC20` interface, +# @dev We import and implement the `IERC20` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC20 -implements: ERC20 +from ethereum.ercs import IERC20 +implements: IERC20 -# @dev We import and implement the `ERC20Detailed` interface, +# @dev We import and implement the `IERC20Detailed` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC20Detailed -implements: ERC20Detailed +from ethereum.ercs import IERC20Detailed +implements: IERC20Detailed # @dev We import and implement the `IERC20Permit` @@ -69,10 +69,10 @@ from ..tokens.interfaces import IERC20Permit implements: IERC20Permit -# @dev We import and implement the `ERC4626` interface, +# @dev We import and implement the `IERC4626` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC4626 -implements: ERC4626 +from ethereum.ercs import IERC4626 +implements: IERC4626 # @dev We import and implement the `IERC5267` interface, @@ -81,72 +81,67 @@ from ..utils.interfaces import IERC5267 implements: IERC5267 -# @dev Constant used as part of the ECDSA recovery function. -_MALLEABILITY_THRESHOLD: constant(bytes32) = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 - - -# @dev The 32-byte type hash for the EIP-712 domain separator. -_TYPE_HASH: constant(bytes32) = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") - - -# @dev The 32-byte type hash of the `permit` function. -_PERMIT_TYPE_HASH: constant(bytes32) = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)") - - -# @dev Returns the name of the token. -# @notice If you declare a variable as `public`, -# Vyper automatically generates an `external` -# getter function for the variable. Furthermore, -# to preserve consistency with the interface for -# the optional metadata functions of the ERC-20 -# standard, we use lower case letters for the -# `immutable` variables `name`, `symbol`, and -# `decimals`. -name: public(immutable(String[25])) - - -# @dev Returns the symbol of the token. -# @notice See comment on lower case letters -# above at `name`. -symbol: public(immutable(String[5])) - - -# @dev Returns the decimals places of the token. -# @notice See comment on lower case letters -# above at `name`. -decimals: public(immutable(uint8)) +# @dev We import the `math` module. +# @notice Please note that the `math` module is stateless +# and therefore does not require the `uses` keyword for usage. +from ..utils import math + + +# @dev We import and initialise the `ownable` module. +# @notice The `ownable` module is merely used to initialise +# the `erc20` module, but none of the associated functions +# are exported. +from ..auth import ownable +initializes: ownable + + +# @dev We import and initialise the `erc20` module. +from ..tokens import erc20 +initializes: erc20[ownable := ownable] + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) the required `external` +# functions from the `erc20` module to implement a compliant +# ERC-20 + EIP-2612 token. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ( + erc20.totalSupply, + erc20.balanceOf, + erc20.transfer, + erc20.transferFrom, + erc20.approve, + erc20.allowance, + erc20.name, + erc20.symbol, + erc20.decimals, + erc20.permit, + erc20.nonces, + erc20.DOMAIN_SEPARATOR, + erc20.eip712Domain, +) # @dev Returns the address of the underlying token # used for the vault for accounting, depositing, # and withdrawing. To preserve consistency with the # ERC-4626 interface, we use lower case letters for -# the `immutable` variable `name`. +# the `immutable` variable `asset`. # @notice Vyper returns the `address` type for interface -# types by default. -asset: public(immutable(ERC20)) - +# types by default. Furthermore, if you declare a +# variable as `public`, Vyper automatically generates +# an `external` getter function for the variable. +asset: public(immutable(address)) -# @dev Caches the domain separator as an `immutable` -# value, but also stores the corresponding chain ID -# to invalidate the cached domain separator if the -# chain ID changes. -_CACHED_DOMAIN_SEPARATOR: immutable(bytes32) -_CACHED_CHAIN_ID: immutable(uint256) - -# @dev Caches `self` to `immutable` storage to avoid -# potential issues if a vanilla contract is used in -# a `delegatecall` context. -_CACHED_SELF: immutable(address) - - -# @dev `immutable` variables to store the (hashed) -# name and (hashed) version during contract creation. -_NAME: immutable(String[50]) -_HASHED_NAME: immutable(bytes32) -_VERSION: immutable(String[20]) -_HASHED_VERSION: immutable(bytes32) +# @dev Stores the ERC-20 interface object of the underlying +# token used for the vault for accounting, depositing, +# and withdrawing. +_ASSET: immutable(IERC20) # @dev An offset in the decimal representation between @@ -162,75 +157,9 @@ _DECIMALS_OFFSET: immutable(uint8) _UNDERLYING_DECIMALS: immutable(uint8) -# @dev Returns the amount of tokens owned by an `address`. -balanceOf: public(HashMap[address, uint256]) - - -# @dev Returns the remaining number of tokens that a -# `spender` will be allowed to spend on behalf of -# `owner` through `transferFrom`. This is zero by -# default. This value changes when `approve` or -# `transferFrom` are called. -allowance: public(HashMap[address, HashMap[address, uint256]]) - - -# @dev Returns the amount of tokens in existence. -totalSupply: public(uint256) - - -# @dev Returns the current on-chain tracked nonce -# of `address`. -nonces: public(HashMap[address, uint256]) - - -# @dev Emitted when `amount` tokens are moved -# from one account (`owner`) to another (`to`). -# Note that the parameter `amount` may be zero. -event Transfer: - owner: indexed(address) - to: indexed(address) - amount: uint256 - - -# @dev Emitted when the allowance of a `spender` -# for an `owner` is set by a call to `approve`. -# The parameter `amount` is the new allowance. -event Approval: - owner: indexed(address) - spender: indexed(address) - amount: uint256 - - -# @dev Emitted when `sender` has exchanged `assets` -# for `shares`, and transferred those `shares` -# to `owner`. -event Deposit: - sender: indexed(address) - owner: indexed(address) - assets: uint256 - shares: uint256 - - -# @dev Emitted when `sender` has exchanged `shares`, -# owned by `owner`, for `assets`, and transferred -# those `assets` to `receiver`. -event Withdraw: - sender: indexed(address) - receiver: indexed(address) - owner: indexed(address) - assets: uint256 - shares: uint256 - - -# @dev May be emitted to signal that the domain could -# have changed. -event EIP712DomainChanged: - pass - - -@external +@deploy @payable -def __init__(name_: String[25], symbol_: String[5], asset_: ERC20, decimals_offset_: uint8, name_eip712_: String[50], version_eip712_: String[20]): +def __init__(name_: String[25], symbol_: String[5], asset_: IERC20, decimals_offset_: uint8, name_eip712_: String[50], version_eip712_: String[20]): """ @dev To omit the opcodes for checking the `msg.value` in the creation-time EVM bytecode, the constructor @@ -252,9 +181,8 @@ def __init__(name_: String[25], symbol_: String[5], asset_: ERC20, decimals_offs main version of the signing domain. Signatures from different versions are not compatible. """ - name = name_ - symbol = symbol_ - asset = asset_ + _ASSET = asset_ + asset = _ASSET.address success: bool = empty(bool) decoded_decimals: uint8 = empty(uint8) @@ -262,112 +190,16 @@ def __init__(name_: String[25], symbol_: String[5], asset_: ERC20, decimals_offs # value of `False` indicates that the attempt failed in # some way. success, decoded_decimals = self._try_get_underlying_decimals(asset_) - _UNDERLYING_DECIMALS = decoded_decimals if success else 18 _DECIMALS_OFFSET = decimals_offset_ + + # Please note that the `ownable` module is merely used to + # initialise the `erc20` module, but none of the associated + # functions are exported. + ownable.__init__() # The following line uses intentionally checked arithmetic # to prevent a theoretically possible overflow. - decimals = _UNDERLYING_DECIMALS + _DECIMALS_OFFSET - - _NAME = name_eip712_ - _VERSION = version_eip712_ - _HASHED_NAME = keccak256(name_eip712_) - _HASHED_VERSION = keccak256(version_eip712_) - _CACHED_DOMAIN_SEPARATOR = self._build_domain_separator() - _CACHED_CHAIN_ID = chain.id - _CACHED_SELF = self - - -@external -def transfer(to: address, amount: uint256) -> bool: - """ - @dev Sourced from {ERC20-transfer}. - @notice See {ERC20-transfer} for the function - docstring. - """ - self._transfer(msg.sender, to, amount) - return True - - -@external -def approve(spender: address, amount: uint256) -> bool: - """ - @dev Sourced from {ERC20-approve}. - @notice See {ERC20-approve} for the function - docstring. - """ - self._approve(msg.sender, spender, amount) - return True - - -@external -def transferFrom(owner: address, to: address, amount: uint256) -> bool: - """ - @dev Sourced from {ERC20-transferFrom}. - @notice See {ERC20-transferFrom} for the function - docstring. - """ - self._spend_allowance(owner, msg.sender, amount) - self._transfer(owner, to, amount) - return True - - -@external -def permit(owner: address, spender: address, amount: uint256, deadline: uint256, v: uint8, r: bytes32, s: bytes32): - """ - @dev Sourced from {ERC20-permit}. - @notice See {ERC20-permit} for the function - docstring. - """ - assert block.timestamp <= deadline, "ERC20Permit: expired deadline" - - current_nonce: uint256 = self.nonces[owner] - self.nonces[owner] = unsafe_add(current_nonce, 1) - - struct_hash: bytes32 = keccak256(_abi_encode(_PERMIT_TYPE_HASH, owner, spender, amount, current_nonce, deadline)) - hash: bytes32 = self._hash_typed_data_v4(struct_hash) - - signer: address = self._recover_vrs(hash, convert(v, uint256), convert(r, uint256), convert(s, uint256)) - assert signer == owner, "ERC20Permit: invalid signature" - - self._approve(owner, spender, amount) - - -@external -@view -def DOMAIN_SEPARATOR() -> bytes32: - """ - @dev Sourced from {ERC20-DOMAIN_SEPARATOR}. - @notice See {ERC20-DOMAIN_SEPARATOR} for the - function docstring. - """ - return self._domain_separator_v4() - - -@external -@view -def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 128]): - """ - @dev Returns the fields and values that describe the domain - separator used by this contract for EIP-712 signatures. - @notice The bits in the 1-byte bit map are read from the least - significant to the most significant, and fields are indexed - in the order that is specified by EIP-712, identical to the - order in which they are listed in the function type. - @return bytes1 The 1-byte bit map where bit `i` is set to 1 - if and only if domain field `i` is present (`0 ≤ i ≤ 4`). - @return String The maximum 50-character user-readable string name - of the signing domain, i.e. the name of the dApp or protocol. - @return String The maximum 20-character current main version of - the signing domain. Signatures from different versions are - not compatible. - @return uint256 The 32-byte EIP-155 chain ID. - @return address The 20-byte address of the verifying contract. - @return bytes32 The 32-byte disambiguation salt for the protocol. - @return DynArray The 32-byte array of EIP-712 extensions. - """ - # Note that `\x0f` equals `01111`. - return (convert(b"\x0f", bytes1), _NAME, _VERSION, chain.id, self, empty(bytes32), empty(DynArray[uint256, 128])) + erc20.__init__(name_, symbol_, _UNDERLYING_DECIMALS + _DECIMALS_OFFSET, name_eip712_, version_eip712_) @external @@ -456,7 +288,7 @@ def deposit(assets: uint256, receiver: address) -> uint256: @param receiver The 20-byte receiver address. @return uint256 The 32-byte shares amount to be created. """ - assert assets <= self._max_deposit(receiver), "ERC4626: deposit more than maximum" + assert assets <= self._max_deposit(receiver), "erc4626: deposit more than maximum" shares: uint256 = self._preview_deposit(assets) self._deposit(msg.sender, receiver, assets, shares) return shares @@ -502,7 +334,7 @@ def mint(shares: uint256, receiver:address) -> uint256: @param receiver The 20-byte receiver address. @return uint256 The deposited 32-byte assets amount. """ - assert shares <= self._max_mint(receiver), "ERC4626: mint more than maximum" + assert shares <= self._max_mint(receiver), "erc4626: mint more than maximum" assets: uint256 = self._preview_mint(shares) self._deposit(msg.sender, receiver, assets, shares) return assets @@ -550,7 +382,7 @@ def withdraw(assets: uint256, receiver: address, owner: address) -> uint256: @param owner The 20-byte owner address. @return uint256 The burned 32-byte shares amount. """ - assert assets <= self._max_withdraw(receiver), "ERC4626: withdraw more than maximum" + assert assets <= self._max_withdraw(receiver), "erc4626: withdraw more than maximum" shares: uint256 = self._preview_withdraw(assets) self._withdraw(msg.sender, receiver, owner, assets, shares) return shares @@ -597,201 +429,15 @@ def redeem(shares: uint256, receiver: address, owner: address) -> uint256: @param owner The 20-byte owner address. @return uint256 The returned 32-byte assets amount. """ - assert shares <= self._max_redeem(owner), "ERC4626: redeem more than maximum" + assert shares <= self._max_redeem(owner), "erc4626: redeem more than maximum" assets: uint256 = self._preview_redeem(shares) self._withdraw(msg.sender, receiver, owner, assets, shares) return assets -@internal -def _transfer(owner: address, to: address, amount: uint256): - """ - @dev Sourced from {ERC20-_transfer}. - @notice See {ERC20-_transfer} for the function - docstring. - """ - assert owner != empty(address), "ERC20: transfer from the zero address" - assert to != empty(address), "ERC20: transfer to the zero address" - - self._before_token_transfer(owner, to, amount) - - owner_balanceOf: uint256 = self.balanceOf[owner] - assert owner_balanceOf >= amount, "ERC20: transfer amount exceeds balance" - self.balanceOf[owner] = unsafe_sub(owner_balanceOf, amount) - self.balanceOf[to] = unsafe_add(self.balanceOf[to], amount) - log Transfer(owner, to, amount) - - self._after_token_transfer(owner, to, amount) - - -@internal -def _mint(owner: address, amount: uint256): - """ - @dev Sourced from {ERC20-_mint}. - @notice See {ERC20-_mint} for the function - docstring. - """ - assert owner != empty(address), "ERC20: mint to the zero address" - - self._before_token_transfer(empty(address), owner, amount) - - self.totalSupply += amount - self.balanceOf[owner] = unsafe_add(self.balanceOf[owner], amount) - log Transfer(empty(address), owner, amount) - - self._after_token_transfer(empty(address), owner, amount) - - -@internal -def _burn(owner: address, amount: uint256): - """ - @dev Sourced from {ERC20-_burn}. - @notice See {ERC20-_burn} for the function - docstring. - """ - assert owner != empty(address), "ERC20: burn from the zero address" - - self._before_token_transfer(owner, empty(address), amount) - - account_balance: uint256 = self.balanceOf[owner] - assert account_balance >= amount, "ERC20: burn amount exceeds balance" - self.balanceOf[owner] = unsafe_sub(account_balance, amount) - self.totalSupply = unsafe_sub(self.totalSupply, amount) - log Transfer(owner, empty(address), amount) - - self._after_token_transfer(owner, empty(address), amount) - - -@internal -def _approve(owner: address, spender: address, amount: uint256): - """ - @dev Sourced from {ERC20-_approve}. - @notice See {ERC20-_approve} for the function - docstring. - """ - assert owner != empty(address), "ERC20: approve from the zero address" - assert spender != empty(address), "ERC20: approve to the zero address" - - self.allowance[owner][spender] = amount - log Approval(owner, spender, amount) - - -@internal -def _spend_allowance(owner: address, spender: address, amount: uint256): - """ - @dev Sourced from {ERC20-_approve}. - @notice See {ERC20-_spend_allowance} for the - function docstring. - """ - current_allowance: uint256 = self.allowance[owner][spender] - if (current_allowance != max_value(uint256)): - # The following line allows the commonly known address - # poisoning attack, where `transferFrom` instructions - # are executed from arbitrary addresses with an `amount` - # of 0. However, this poisoning attack is not an on-chain - # vulnerability. All assets are safe. It is an off-chain - # log interpretation issue. - assert current_allowance >= amount, "ERC20: insufficient allowance" - self._approve(owner, spender, unsafe_sub(current_allowance, amount)) - - -@internal -def _before_token_transfer(owner: address, to: address, amount: uint256): - """ - @dev Sourced from {ERC20-_before_token_transfer}. - @notice See {ERC20-_before_token_transfer} for - the function docstring. - """ - pass - - -@internal -def _after_token_transfer(owner: address, to: address, amount: uint256): - """ - @dev Sourced from {ERC20-_after_token_transfer}. - @notice See {ERC20-_after_token_transfer} for - the function docstring. - """ - pass - - -@internal -@view -def _domain_separator_v4() -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-domain_separator_v4}. - @notice See {EIP712DomainSeparator-domain_separator_v4} - for the function docstring. - """ - if (self == _CACHED_SELF and chain.id == _CACHED_CHAIN_ID): - return _CACHED_DOMAIN_SEPARATOR - else: - return self._build_domain_separator() - - -@internal -@view -def _build_domain_separator() -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-_build_domain_separator}. - @notice See {EIP712DomainSeparator-_build_domain_separator} - for the function docstring. - """ - return keccak256(_abi_encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, chain.id, self)) - - -@internal -@view -def _hash_typed_data_v4(struct_hash: bytes32) -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-hash_typed_data_v4}. - @notice See {EIP712DomainSeparator-hash_typed_data_v4} - for the function docstring. - """ - return self._to_typed_data_hash(self._domain_separator_v4(), struct_hash) - - -@internal -@pure -def _to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32: - """ - @dev Sourced from {ECDSA-to_typed_data_hash}. - @notice See {ECDSA-to_typed_data_hash} for the - function docstring. - """ - return keccak256(concat(b"\x19\x01", domain_separator, struct_hash)) - - -@internal -@pure -def _recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Sourced from {ECDSA-_recover_vrs}. - @notice See {ECDSA-_recover_vrs} for the - function docstring. - """ - return self._try_recover_vrs(hash, v, r, s) - - -@internal -@pure -def _try_recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Sourced from {ECDSA-_try_recover_vrs}. - @notice See {ECDSA-_try_recover_vrs} for the - function docstring. - """ - assert s <= convert(_MALLEABILITY_THRESHOLD, uint256), "ECDSA: invalid signature `s` value" - - signer: address = ecrecover(hash, v, r, s) - assert signer != empty(address), "ECDSA: invalid signature" - - return signer - - @internal @view -def _try_get_underlying_decimals(underlying: ERC20) -> (bool, uint8): +def _try_get_underlying_decimals(underlying: IERC20) -> (bool, uint8): """ @dev Attempts to fetch the underlying's decimals. A return value of `False` indicates that the attempt failed in @@ -829,7 +475,7 @@ def _total_assets() -> uint256: https://eips.ethereum.org/EIPS/eip-4626#totalassets. @return uint256 The 32-byte total managed assets. """ - return asset.balanceOf(self) + return staticcall _ASSET.balanceOf(self) @internal @@ -843,7 +489,7 @@ def _convert_to_shares(assets: uint256, roundup: bool) -> uint256: to round up or not. The default `False` is round down. @return uint256 The converted 32-byte shares amount. """ - return self._mul_div(assets, self.totalSupply + 10 ** convert(_DECIMALS_OFFSET, uint256), self._total_assets() + 1, roundup) + return math._mul_div(assets, erc20.totalSupply + 10 ** convert(_DECIMALS_OFFSET, uint256), self._total_assets() + 1, roundup) @internal @@ -857,7 +503,7 @@ def _convert_to_assets(shares: uint256, roundup: bool) -> uint256: to round up or not. The default `False` is round down. @return uint256 The converted 32-byte assets amount. """ - return self._mul_div(shares, self._total_assets() + 1, self.totalSupply + 10 ** convert(_DECIMALS_OFFSET, uint256), roundup) + return math._mul_div(shares, self._total_assets() + 1, erc20.totalSupply + 10 ** convert(_DECIMALS_OFFSET, uint256), roundup) @internal @@ -932,7 +578,7 @@ def _max_withdraw(owner: address) -> uint256: @param owner The 20-byte owner address. @return uint256 The 32-byte maximum withdraw amount. """ - return self._convert_to_assets(self.balanceOf[owner], False) + return self._convert_to_assets(erc20.balanceOf[owner], False) @internal @@ -962,7 +608,7 @@ def _max_redeem(owner: address) -> uint256: @param owner The 20-byte owner address. @return uint256 The 32-byte maximum redeemable shares amount. """ - return self.balanceOf[owner] + return erc20.balanceOf[owner] @internal @@ -1000,7 +646,7 @@ def _deposit(sender: address, receiver: address, assets: uint256, shares: uint25 # To deal with (potentially) non-compliant ERC-20 tokens that do have # no return value, we use the kwarg `default_return_value` for external - # calls. This function was introduced in Vyper version 0.3.4. For more + # calls. This function was introduced in Vyper version `0.3.4`. For more # details see: # - https://github.com/vyperlang/vyper/pull/2839, # - https://github.com/vyperlang/vyper/issues/2812, @@ -1010,9 +656,9 @@ def _deposit(sender: address, receiver: address, assets: uint256, shares: uint25 # always performs an external code size check on the target address unless # you add the kwarg `skip_contract_check=True`. If the check fails (i.e. # the target address is an EOA), the call reverts. - assert asset.transferFrom(sender, self, assets, default_return_value=True), "ERC4626: transferFrom operation did not succeed" - self._mint(receiver, shares) - log Deposit(sender, receiver, assets, shares) + assert extcall _ASSET.transferFrom(sender, self, assets, default_return_value=True), "erc4626: transferFrom operation did not succeed" + erc20._mint(receiver, shares) + log IERC4626.Deposit(sender, receiver, assets, shares) @internal @@ -1027,7 +673,7 @@ def _withdraw(sender: address, receiver: address, owner: address, assets: uint25 @param shares The 32-byte shares amount. """ if (sender != owner): - self._spend_allowance(owner, sender, shares) + erc20._spend_allowance(owner, sender, shares) # If `asset` is an ERC-777, `transfer` can trigger a reentrancy # after the transfer happens through the `tokensReceived` hook. @@ -1036,11 +682,11 @@ def _withdraw(sender: address, receiver: address, owner: address, assets: uint25 # be malicious. Thus, we need to do the transfer after the burn # so that any reentrancy would happen after the shares are burned # and after the assets are transferred, which is a valid state. - self._burn(owner, shares) + erc20._burn(owner, shares) # To deal with (potentially) non-compliant ERC-20 tokens that do have # no return value, we use the kwarg `default_return_value` for external - # calls. This function was introduced in Vyper version 0.3.4. For more + # calls. This function was introduced in Vyper version `0.3.4`. For more # details see: # - https://github.com/vyperlang/vyper/pull/2839, # - https://github.com/vyperlang/vyper/issues/2812, @@ -1050,113 +696,5 @@ def _withdraw(sender: address, receiver: address, owner: address, assets: uint25 # always performs an external code size check on the target address unless # you add the kwarg `skip_contract_check=True`. If the check fails (i.e. # the target address is an EOA), the call reverts. - assert asset.transfer(receiver, assets, default_return_value=True), "ERC4626: transfer operation did not succeed" - log Withdraw(sender, receiver, owner, assets, shares) - - -@internal -@pure -def _mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint256: - """ - @dev Sourced from {Math-mul_div}. - @notice See {Math-mul_div} for the function - docstring. - """ - # Handle division by zero. - assert denominator != empty(uint256), "Math: mul_div division by zero" - - # 512-bit multiplication "[prod1 prod0] = x * y". - # Compute the product "mod 2**256" and "mod 2**256 - 1". - # Then use the Chinese Remainder theorem to reconstruct - # the 512-bit result. The result is stored in two 256-bit - # variables, where: "product = prod1 * 2**256 + prod0". - mm: uint256 = uint256_mulmod(x, y, max_value(uint256)) - # The least significant 256 bits of the product. - prod0: uint256 = unsafe_mul(x, y) - # The most significant 256 bits of the product. - prod1: uint256 = empty(uint256) - - if (mm < prod0): - prod1 = unsafe_sub(unsafe_sub(mm, prod0), 1) - else: - prod1 = unsafe_sub(mm, prod0) - - # Handling of non-overflow cases, 256 by 256 division. - if (prod1 == empty(uint256)): - if (roundup and uint256_mulmod(x, y, denominator) != empty(uint256)): - # Calculate "ceil((x * y) / denominator)". The following - # line cannot overflow because we have the previous check - # "(x * y) % denominator != 0", which accordingly rules out - # the possibility of "x * y = 2**256 - 1" and `denominator == 1`. - return unsafe_add(unsafe_div(prod0, denominator), 1) - else: - return unsafe_div(prod0, denominator) - - # Ensure that the result is less than 2**256. Also, - # prevents that `denominator == 0`. - assert denominator > prod1, "Math: mul_div overflow" - - ####################### - # 512 by 256 Division # - ####################### - - # Make division exact by subtracting the remainder - # from "[prod1 prod0]". First, compute remainder using - # the `uint256_mulmod` operation. - remainder: uint256 = uint256_mulmod(x, y, denominator) - - # Second, subtract the 256-bit number from the 512-bit - # number. - if (remainder > prod0): - prod1 = unsafe_sub(prod1, 1) - prod0 = unsafe_sub(prod0, remainder) - - # Factor powers of two out of the denominator and calculate - # the largest power of two divisor of denominator. Always `>= 1`, - # unless the denominator is zero (which is prevented above), - # in which case `twos` is zero. For more details, please refer to: - # https://cs.stackexchange.com/q/138556. - twos: uint256 = unsafe_sub(0, denominator) & denominator - # Divide denominator by `twos`. - denominator_div: uint256 = unsafe_div(denominator, twos) - # Divide "[prod1 prod0]" by `twos`. - prod0 = unsafe_div(prod0, twos) - # Flip `twos` such that it is "2**256 / twos". If `twos` is zero, - # it becomes one. - twos = unsafe_add(unsafe_div(unsafe_sub(empty(uint256), twos), twos), 1) - - # Shift bits from `prod1` to `prod0`. - prod0 |= unsafe_mul(prod1, twos) - - # Invert the denominator "mod 2**256". Since the denominator is - # now an odd number, it has an inverse modulo 2**256, so we have: - # "denominator * inverse = 1 mod 2**256". Calculate the inverse by - # starting with a seed that is correct for four bits. That is, - # "denominator * inverse = 1 mod 2**4". - inverse: uint256 = unsafe_mul(3, denominator_div) ^ 2 - - # Use Newton-Raphson iteration to improve accuracy. Thanks to Hensel's - # lifting lemma, this also works in modular arithmetic by doubling the - # correct bits in each step. - inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**8". - inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**16". - inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**32". - inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**64". - inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**128". - inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**256". - - # Since the division is now exact, we can divide by multiplying - # with the modular inverse of the denominator. This returns the - # correct result modulo 2**256. Since the preconditions guarantee - # that the result is less than 2**256, this is the final result. - # We do not need to calculate the high bits of the result and - # `prod1` is no longer necessary. - result: uint256 = unsafe_mul(prod0, inverse) - - if (roundup and uint256_mulmod(x, y, denominator) != empty(uint256)): - # Calculate "ceil((x * y) / denominator)". The following - # line uses intentionally checked arithmetic to prevent - # a theoretically possible overflow. - result += 1 - - return result + assert extcall _ASSET.transfer(receiver, assets, default_return_value=True), "erc4626: transfer operation did not succeed" + log IERC4626.Withdraw(sender, receiver, owner, assets, shares) diff --git a/src/snekmate/extensions/interfaces/IERC2981.vy b/src/snekmate/extensions/interfaces/IERC2981.vyi similarity index 90% rename from src/snekmate/extensions/interfaces/IERC2981.vy rename to src/snekmate/extensions/interfaces/IERC2981.vyi index f4ba3dd2..71fbe654 100644 --- a/src/snekmate/extensions/interfaces/IERC2981.vy +++ b/src/snekmate/extensions/interfaces/IERC2981.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-2981 Interface Definition @custom:contract-name IERC2981 @@ -17,10 +17,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 @external @@ -36,7 +36,7 @@ def supportsInterface(interfaceId: bytes4) -> bool: @return bool The verification whether the contract implements the interface or not. """ - return empty(bool) + return ... @external @@ -55,4 +55,4 @@ def royaltyInfo(_tokenId: uint256, _salePrice: uint256) -> (address, uint256): @return uint256 The 32-byte royalty payment amount for `_salePrice`. """ - return (empty(address), empty(uint256)) + return ... diff --git a/src/snekmate/extensions/mocks/erc2981_mock.vy b/src/snekmate/extensions/mocks/erc2981_mock.vy new file mode 100644 index 00000000..44e5dd1e --- /dev/null +++ b/src/snekmate/extensions/mocks/erc2981_mock.vy @@ -0,0 +1,93 @@ +# pragma version ~=0.4.0rc6 +""" +@title `erc2981` Module Reference Implementation +@custom:contract-name erc2981_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and implement the `IERC165` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC165 +implements: IERC165 + + +# @dev We import and implement the `IERC2981` interface, +# which is written using standard Vyper syntax. +from ..interfaces import IERC2981 +implements: IERC2981 + + +# @dev We import and initialise the `ownable` module. +from ...auth import ownable as ow +initializes: ow + + +# @dev We import and initialise the `erc2981` module. +from .. import erc2981 +initializes: erc2981[ownable := ow] + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `erc2981` module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ( + # @notice If you are integrating this contract with an + # ERC-721 or ERC-1155 contract, please ensure you include + # the additional ERC-165 interface identifiers into the + # function `supportsInterface`. One way to achieve this + # would be to not export the `supportsInterface` function + # from {erc2981} in the main contract and implement the + # following function in the main contract instead: + # ```vy + # @external + # @view + # def supportsInterface(interface_id: bytes4) -> bool: + # return ((interface_id in erc2981._SUPPORTED_INTERFACES) or (interface_id in [0x..., ...])) + # ``` + erc2981.supportsInterface, + erc2981.owner, + # @notice If you integrate the function `transfer_ownership` + # into an ERC-721 or ERC-1155 contract that implements an + # `is_minter` role, ensure that the previous owner's minter + # role is also removed and the minter role is assigned to the + # `new_owner` accordingly. + erc2981.transfer_ownership, + # @notice If you integrate the function `renounce_ownership` + # into an ERC-721 or ERC-1155 contract that implements an + # `is_minter` role, ensure that the previous owner's minter + # role as well as all non-owner minter addresses are also + # removed before calling `renounce_ownership`. + erc2981.renounce_ownership, + erc2981.royaltyInfo, + erc2981.set_default_royalty, + erc2981.delete_default_royalty, + erc2981.set_token_royalty, + erc2981.reset_token_royalty, +) + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @notice The `owner` role will be assigned to the + `msg.sender`. Furthermore, the default value + of {erc2981-_fee_denominator} is set to `10_000`. + """ + # The following line assigns the `owner` + # to the `msg.sender`. + ow.__init__() + # The following line sets the default value + # of {erc2981-_fee_denominator} to `10_000` + # so that the fee is in basis points by default. + erc2981.__init__() diff --git a/src/snekmate/extensions/mocks/erc4626_mock.vy b/src/snekmate/extensions/mocks/erc4626_mock.vy new file mode 100644 index 00000000..07c55fc5 --- /dev/null +++ b/src/snekmate/extensions/mocks/erc4626_mock.vy @@ -0,0 +1,88 @@ +# pragma version ~=0.4.0rc6 +""" +@title `erc4626` Module Reference Implementation +@custom:contract-name erc4626_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and implement the `IERC20` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC20 +implements: IERC20 + + +# @dev We import and implement the `IERC20Detailed` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC20Detailed +implements: IERC20Detailed + + +# @dev We import and implement the `IERC20Permit` +# interface, which is written using standard Vyper +# syntax. +from ...tokens.interfaces import IERC20Permit +implements: IERC20Permit + + +# @dev We import and implement the `IERC4626` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC4626 +implements: IERC4626 + + +# @dev We import and implement the `IERC5267` interface, +# which is written using standard Vyper syntax. +from ...utils.interfaces import IERC5267 +implements: IERC5267 + + +# @dev We import and initialise the `erc4626` module. +from .. import erc4626 +initializes: erc4626 + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `erc4626` module. The built-in dunder method +# `__interface__` allows you to export all functions of a +# module without specifying the individual functions (see +# https://github.com/vyperlang/vyper/pull/3919). Please take +# note that if you do not know the full interface of a module +# contract, you can get the `.vyi` interface in Vyper by using +# `vyper -f interface your_filename.vy` or the external interface +# by using `vyper -f external_interface your_filename.vy`. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: erc4626.__interface__ + + +@deploy +@payable +def __init__(name_: String[25], symbol_: String[5], asset_: IERC20, decimals_offset_: uint8, name_eip712_: String[50], version_eip712_: String[20]): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @param name_ The maximum 25-character user-readable + string name of the token. + @param symbol_ The maximum 5-character user-readable + string symbol of the token. + @param asset_ The ERC-20 compatible (i.e. ERC-777 is also viable) + underlying asset contract. + @param decimals_offset_ The 1-byte offset in the decimal + representation between the underlying asset's + decimals and the vault decimals. The recommended value to + mitigate the risk of an inflation attack is `0`. + @param name_eip712_ The maximum 50-character user-readable + string name of the signing domain, i.e. the name + of the dApp or protocol. + @param version_eip712_ The maximum 20-character current + main version of the signing domain. Signatures + from different versions are not compatible. + """ + erc4626.__init__(name_, symbol_, asset_, decimals_offset_, name_eip712_, version_eip712_) diff --git a/src/snekmate/governance/mocks/timelock_controller_mock.vy b/src/snekmate/governance/mocks/timelock_controller_mock.vy new file mode 100644 index 00000000..8ade082f --- /dev/null +++ b/src/snekmate/governance/mocks/timelock_controller_mock.vy @@ -0,0 +1,99 @@ +# pragma version ~=0.4.0rc6 +""" +@title `timelock_controller` Module Reference Implementation +@custom:contract-name timelock_controller_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and implement the `IERC165` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC165 +implements: IERC165 + + +# @dev We import and implement the `IAccessControl` +# interface, which is written using standard Vyper +# syntax. +from ...auth.interfaces import IAccessControl +implements: IAccessControl + + +# @dev We import and implement the `IERC721Receiver` +# interface, which is written using standard Vyper +# syntax. +from ...tokens.interfaces import IERC721Receiver +implements: IERC721Receiver + + +# @dev We import and implement the `IERC1155Receiver` +# interface, which is written using standard Vyper +# syntax. +from ...tokens.interfaces import IERC1155Receiver +implements: IERC1155Receiver + + +# @dev We import and initialise the `access_control` module. +from ...auth import access_control as ac +initializes: ac + + +# @dev We import and initialise the `timelock_controller` module. +from .. import timelock_controller as tc +initializes: tc[access_control := ac] + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `timelock_controller` module. The built-in dunder +# method `__interface__` allows you to export all functions +# of a module without specifying the individual functions (see +# https://github.com/vyperlang/vyper/pull/3919). Please take +# note that if you do not know the full interface of a module +# contract, you can get the `.vyi` interface in Vyper by using +# `vyper -f interface your_filename.vy` or the external interface +# by using `vyper -f external_interface your_filename.vy`. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: tc.__interface__ + + +@deploy +@payable +def __init__(minimum_delay_: uint256, proposers_: DynArray[address, tc._DYNARRAY_BOUND], executors_: DynArray[address, tc._DYNARRAY_BOUND], admin_: address): + """ + @dev Initialises the contract with the following parameters: + - `minimum_delay_`: The initial minimum delay in seconds + for operations, + - `proposers_`: The accounts to be granted proposer and + canceller roles, + - `executors_`: The accounts to be granted executor role, + - `admin_`: The optional account to be granted admin role + (disable with the zero address). + + IMPORTANT: The optional admin can aid with initial + configuration of roles after deployment without being + subject to delay, but this role should be subsequently + renounced in favor of administration through timelocked + proposals. + + To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @param minimum_delay_ The 32-byte minimum delay in seconds + for operations. + @param proposers_ The 20-byte array of accounts to be granted + proposer and canceller roles. + @param executors_ The 20-byte array of accounts to be granted + executor role. + @param admin_ The 20-byte (optional) account to be granted admin + role. + """ + # The following line assigns the `DEFAULT_ADMIN_ROLE` + # to the `msg.sender`. + ac.__init__() + tc.__init__(minimum_delay_, proposers_, executors_, admin_) diff --git a/src/snekmate/governance/TimelockController.vy b/src/snekmate/governance/timelock_controller.vy similarity index 80% rename from src/snekmate/governance/TimelockController.vy rename to src/snekmate/governance/timelock_controller.vy index b3d2d728..5983cce8 100644 --- a/src/snekmate/governance/TimelockController.vy +++ b/src/snekmate/governance/timelock_controller.vy @@ -1,13 +1,13 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Multi-Role-Based Timelock Controller Reference Implementation -@custom:contract-name TimelockController +@custom:contract-name timelock_controller @license GNU Affero General Public License v3.0 only @author pcaversaccio @custom:coauthor cairoeth @notice This module enables the timelocking of operations by scheduling - and executing transactions. By leveraging `AccessControl`, the - `TimelockController` contract introduces three roles: + and executing transactions. By leveraging `access_control`, the + `timelock_controller` contract introduces three roles: 1. proposer (`PROPOSER_ROLE`), 2. executor (`EXECUTOR_ROLE`), and 3. canceller (`CANCELLER_ROLE`). @@ -32,7 +32,7 @@ The latter is useful for processes that have to be executed in the same block. - Please note that the `TimelockController` contract is able to receive + Please note that the `timelock_controller` contract is able to receive and transfer ERC-721 and ERC-1155 tokens. The implementation is inspired by OpenZeppelin's implementation here: @@ -40,10 +40,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 # @dev We import and implement the `IAccessControl` @@ -67,15 +67,36 @@ from ..tokens.interfaces import IERC1155Receiver implements: IERC1155Receiver -# @dev The default 32-byte admin role. -# @notice If you declare a variable as `public`, -# Vyper automatically generates an `external` -# getter function for the variable. -DEFAULT_ADMIN_ROLE: public(constant(bytes32)) = empty(bytes32) +# @dev We import and use the `access_control` module. +from ..auth import access_control +uses: access_control + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# (with the exception of the `supportsInterface` function) +# from the `access_control` module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ( + access_control.DEFAULT_ADMIN_ROLE, + access_control.hasRole, + access_control.getRoleAdmin, + access_control.grantRole, + access_control.revokeRole, + access_control.renounceRole, + access_control.set_role_admin, +) # @dev The 32-byte proposer role. # @notice Responsible for proposing operations. +# If you declare a variable as `public`, +# Vyper automatically generates an `external` +# getter function for the variable. PROPOSER_ROLE: public(constant(bytes32)) = keccak256("PROPOSER_ROLE") @@ -126,15 +147,15 @@ _DYNARRAY_BOUND: constant(uint8) = max_value(uint8) # @dev The possible states of a proposal. -# @notice Enums are treated differently in Vyper and -# Solidity. The members are represented by `uint256` -# values (in Solidity the values are of type `uint8`) -# in the form `2**n`, where `n` is the index of the -# member in the range `0 <= n <= 255` (i.e. the first +# @notice Flags (a.k.a. Enums) are treated differently +# in Vyper and Solidity. The members are represented by +# `uint256` values (in Solidity the values are of type +# `uint8`) in the form `2**n`, where `n` is the index of +# the member in the range `0 <= n <= 255` (i.e. the first # index value is `1`). For further insights also, see -# the following Twitter thread: +# the following X thread: # https://x.com/pcaversaccio/status/1626514029094047747. -enum OperationState: +flag OperationState: UNSET WAITING READY @@ -153,14 +174,6 @@ get_timestamp: public(HashMap[bytes32, uint256]) get_minimum_delay: public(uint256) -# @dev Returns `True` if `account` has been granted `role`. -hasRole: public(HashMap[bytes32, HashMap[address, bool]]) - - -# @dev Returns the admin role that controls `role`. -getRoleAdmin: public(HashMap[bytes32, bytes32]) - - # @dev Emitted when a call is scheduled as part of # operation `id`. Note that `index` is the index # position of the proposal. If the proposal is @@ -206,40 +219,7 @@ event MinimumDelayChange: new_duration: uint256 -# @dev Emitted when `new_admin_role` is set as -# `role`'s admin role, replacing `previous_admin_role`. -# Note that `DEFAULT_ADMIN_ROLE` is the starting -# admin for all roles, despite `RoleAdminChanged` -# not being emitted signaling this. -event RoleAdminChanged: - role: indexed(bytes32) - previous_admin_role: indexed(bytes32) - new_admin_role: indexed(bytes32) - - -# @dev Emitted when `account` is granted `role`. -# Note that `sender` is the account (an admin -# role bearer) that originated the contract call. -event RoleGranted: - role: indexed(bytes32) - account: indexed(address) - sender: indexed(address) - - -# @dev Emitted when `account` is revoked `role`. -# Note that `sender` is the account that originated -# the contract call: -# - if using `revokeRole`, it is the admin role -# bearer, -# - if using `renounceRole`, it is the role bearer -# (i.e. `account`). -event RoleRevoked: - role: indexed(bytes32) - account: indexed(address) - sender: indexed(address) - - -@external +@deploy @payable def __init__(minimum_delay_: uint256, proposers_: DynArray[address, _DYNARRAY_BOUND], executors_: DynArray[address, _DYNARRAY_BOUND], admin_: address): """ @@ -271,20 +251,20 @@ def __init__(minimum_delay_: uint256, proposers_: DynArray[address, _DYNARRAY_BO role. """ # Configure the contract to be self-administered. - self._grant_role(DEFAULT_ADMIN_ROLE, self) + access_control._grant_role(access_control.DEFAULT_ADMIN_ROLE, self) # Set the optional admin. if (admin_ != empty(address)): - self._grant_role(DEFAULT_ADMIN_ROLE, admin_) + access_control._grant_role(access_control.DEFAULT_ADMIN_ROLE, admin_) # Register the proposers and cancellers. - for proposer in proposers_: - self._grant_role(PROPOSER_ROLE, proposer) - self._grant_role(CANCELLER_ROLE, proposer) + for proposer: address in proposers_: + access_control._grant_role(PROPOSER_ROLE, proposer) + access_control._grant_role(CANCELLER_ROLE, proposer) # Register the executors. - for executor in executors_: - self._grant_role(EXECUTOR_ROLE, executor) + for executor: address in executors_: + access_control._grant_role(EXECUTOR_ROLE, executor) # Set the minimum delay. self.get_minimum_delay = minimum_delay_ @@ -434,7 +414,7 @@ def schedule(target: address, amount: uint256, payload: Bytes[1_024], predecesso @param delay The 32-byte delay before the operation becomes valid. Must be greater than or equal to the minimum delay. """ - self._check_role(PROPOSER_ROLE, msg.sender) + access_control._check_role(PROPOSER_ROLE, msg.sender) id: bytes32 = self._hash_operation(target, amount, payload, predecessor, salt) self._schedule(id, delay) @@ -462,13 +442,13 @@ def schedule_batch(targets: DynArray[address, _DYNARRAY_BOUND], amounts: DynArra @param delay The 32-byte delay before the operation becomes valid. Must be greater than or equal to the minimum delay. """ - self._check_role(PROPOSER_ROLE, msg.sender) - assert len(targets) == len(amounts) and len(targets) == len(payloads), "TimelockController: length mismatch" + access_control._check_role(PROPOSER_ROLE, msg.sender) + assert ((len(targets) == len(amounts)) and (len(targets) == len(payloads))), "timelock_controller: length mismatch" id: bytes32 = self._hash_operation_batch(targets, amounts, payloads, predecessor, salt) self._schedule(id, delay) idx: uint256 = empty(uint256) - for target in targets: + for target: address in targets: log CallScheduled(id, idx, target, amounts[idx], payloads[idx], predecessor, delay) # The following line cannot overflow because we have # limited the dynamic array `targets` by the `constant` @@ -486,8 +466,8 @@ def cancel(id: bytes32): @notice Note that the caller must have the `CANCELLER_ROLE` role. @param id The 32-byte operation identifier. """ - self._check_role(CANCELLER_ROLE, msg.sender) - assert self._is_operation_pending(id), "TimelockController: operation cannot be cancelled" + access_control._check_role(CANCELLER_ROLE, msg.sender) + assert self._is_operation_pending(id), "timelock_controller: operation cannot be cancelled" self.get_timestamp[id] = empty(uint256) log Cancelled(id) @@ -542,12 +522,12 @@ def execute_batch(targets: DynArray[address, _DYNARRAY_BOUND], amounts: DynArray the operation during reentrancy are caught. """ self._only_role_or_open_role(EXECUTOR_ROLE) - assert len(targets) == len(amounts) and len(targets) == len(payloads), "TimelockController: length mismatch" + assert ((len(targets) == len(amounts)) and (len(targets) == len(payloads))), "timelock_controller: length mismatch" id: bytes32 = self._hash_operation_batch(targets, amounts, payloads, predecessor, salt) self._before_call(id, predecessor) idx: uint256 = empty(uint256) - for target in targets: + for target: address in targets: self._execute(target, amounts[idx], payloads[idx]) log CallExecuted(id, idx, target, amounts[idx], payloads[idx]) # The following line cannot overflow because we have @@ -563,62 +543,18 @@ def update_delay(new_delay: uint256): """ @dev Changes the minimum timelock duration for future operations. Emits a `MinimumDelayChange` event. - @notice Note that the caller must be the `TimelockController` + @notice Note that the caller must be the `timelock_controller` contract itself. This can only be achieved by scheduling - and later executing an operation where the `TimelockController` + and later executing an operation where the `timelock_controller` contract is the target and the payload is the ABI-encoded call to this function. @param new_delay The new 32-byte minimum delay in seconds. """ - assert msg.sender == self, "TimelockController: caller must be timelock" + assert msg.sender == self, "timelock_controller: caller must be timelock" log MinimumDelayChange(self.get_minimum_delay, new_delay) self.get_minimum_delay = new_delay -@external -def grantRole(role: bytes32, account: address): - """ - @dev Sourced from {AccessControl-grantRole}. - @notice See {AccessControl-grantRole} for the - function docstring. - """ - self._check_role(self.getRoleAdmin[role], msg.sender) - self._grant_role(role, account) - - -@external -def revokeRole(role: bytes32, account: address): - """ - @dev Sourced from {AccessControl-revokeRole}. - @notice See {AccessControl-revokeRole} for the - function docstring. - """ - self._check_role(self.getRoleAdmin[role], msg.sender) - self._revoke_role(role, account) - - -@external -def renounceRole(role: bytes32, account: address): - """ - @dev Sourced from {AccessControl-renounceRole}. - @notice See {AccessControl-renounceRole} for the - function docstring. - """ - assert account == msg.sender, "AccessControl: can only renounce roles for itself" - self._revoke_role(role, account) - - -@external -def set_role_admin(role: bytes32, admin_role: bytes32): - """ - @dev Sourced from {AccessControl-set_role_admin}. - @notice See {AccessControl-set_role_admin} for the - function docstring. - """ - self._check_role(self.getRoleAdmin[role], msg.sender) - self._set_role_admin(role, admin_role) - - @external def onERC721Received(operator: address, owner: address, token_id: uint256, data: Bytes[1_024]) -> bytes4: """ @@ -719,7 +655,7 @@ def _is_operation_pending(id: bytes32) -> bool: is pending or not. """ state: OperationState = self._get_operation_state(id) - return state == OperationState.WAITING or state == OperationState.READY + return ((state == OperationState.WAITING) or (state == OperationState.READY)) @internal @@ -764,8 +700,8 @@ def _get_operation_state(id: bytes32) -> OperationState: return OperationState.DONE elif (timestamp > block.timestamp): return OperationState.WAITING - else: - return OperationState.READY + + return OperationState.READY @internal @@ -818,8 +754,8 @@ def _schedule(id: bytes32, delay: uint256): becomes valid. Must be greater than or equal to the minimum delay. """ - assert not(self._is_operation(id)), "TimelockController: operation already scheduled" - assert delay >= self.get_minimum_delay, "TimelockController: insufficient delay" + assert not(self._is_operation(id)), "timelock_controller: operation already scheduled" + assert delay >= self.get_minimum_delay, "timelock_controller: insufficient delay" self.get_timestamp[id] = block.timestamp + delay @@ -838,11 +774,11 @@ def _execute(target: address, amount: uint256, payload: Bytes[1_024]): success: bool = empty(bool) success, return_data = raw_call(target, payload, max_outsize=255, value=amount, revert_on_failure=False) if (not(success)): - if len(return_data) != empty(uint256): + if (len(return_data) != empty(uint256)): # Bubble up the revert reason. raw_revert(return_data) - else: - raise "TimelockController: underlying transaction reverted" + + raise "timelock_controller: underlying transaction reverted" @internal @@ -855,8 +791,8 @@ def _before_call(id: bytes32, predecessor: bytes32): @param predecessor The 32-byte hash of the preceding operation. """ - assert self._is_operation_ready(id), "TimelockController: operation is not ready" - assert predecessor == empty(bytes32) or self._is_operation_done(predecessor), "TimelockController: missing dependency" + assert self._is_operation_ready(id), "timelock_controller: operation is not ready" + assert ((predecessor == empty(bytes32)) or (self._is_operation_done(predecessor))), "timelock_controller: missing dependency" @internal @@ -866,7 +802,7 @@ def _after_call(id: bytes32): executing (an) operation call(s). @param id The 32-byte operation identifier. """ - assert self._is_operation_ready(id), "TimelockController: operation is not ready" + assert self._is_operation_ready(id), "timelock_controller: operation is not ready" self.get_timestamp[id] = _DONE_TIMESTAMP @@ -881,52 +817,5 @@ def _only_role_or_open_role(role: bytes32): enabling this role for everyone. @param role The 32-byte role definition. """ - if (not(self.hasRole[role][empty(address)])): - self._check_role(role, msg.sender) - - -@internal -@view -def _check_role(role: bytes32, account: address): - """ - @dev Sourced from {AccessControl-_check_role}. - @notice See {AccessControl-_check_role} for the - function docstring. - """ - assert self.hasRole[role][account], "AccessControl: account is missing role" - - -@internal -def _set_role_admin(role: bytes32, admin_role: bytes32): - """ - @dev Sourced from {AccessControl-_set_role_admin}. - @notice See {AccessControl-_set_role_admin} for the - function docstring. - """ - previous_admin_role: bytes32 = self.getRoleAdmin[role] - self.getRoleAdmin[role] = admin_role - log RoleAdminChanged(role, previous_admin_role, admin_role) - - -@internal -def _grant_role(role: bytes32, account: address): - """ - @dev Sourced from {AccessControl-_grant_role}. - @notice See {AccessControl-_grant_role} for the - function docstring. - """ - if (not(self.hasRole[role][account])): - self.hasRole[role][account] = True - log RoleGranted(role, account, msg.sender) - - -@internal -def _revoke_role(role: bytes32, account: address): - """ - @dev Sourced from {AccessControl-_revoke_role}. - @notice See {AccessControl-_revoke_role} for the - function docstring. - """ - if (self.hasRole[role][account]): - self.hasRole[role][account] = False - log RoleRevoked(role, account, msg.sender) + if (not(access_control.hasRole[role][empty(address)])): + access_control._check_role(role, msg.sender) diff --git a/src/snekmate/tokens/ERC1155.vy b/src/snekmate/tokens/erc1155.vy similarity index 81% rename from src/snekmate/tokens/ERC1155.vy rename to src/snekmate/tokens/erc1155.vy index 1741e467..8f60121b 100644 --- a/src/snekmate/tokens/ERC1155.vy +++ b/src/snekmate/tokens/erc1155.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Modern and Gas-Efficient ERC-1155 Implementation -@custom:contract-name ERC1155 +@custom:contract-name erc1155 @license GNU Affero General Public License v3.0 only @author pcaversaccio @custom:coauthor jtriley.eth @@ -32,10 +32,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 # @dev We import and implement the `IERC1155` interface, @@ -56,10 +56,35 @@ implements: IERC1155MetadataURI import interfaces.IERC1155Receiver as IERC1155Receiver +# @dev We import and use the `ownable` module. +from ..auth import ownable +uses: ownable + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) the `external` getter +# function `owner` from the `ownable` module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ( + # @notice This ERC-1155 implementation includes the `transfer_ownership` + # and `renounce_ownership` functions, which incorporate + # the additional built-in `is_minter` role logic and are + # therefore not exported from the `ownable` module. + ownable.owner, +) + + # @dev Stores the ERC-165 interface identifier for each # imported interface. The ERC-165 interface identifier # is defined as the XOR of all function selectors in the # interface. +# @notice If you are not using the full feature set of +# this contract, please ensure you exclude the unused +# ERC-165 interface identifiers in the main contract. _SUPPORTED_INTERFACES: constant(bytes4[3]) = [ 0x01FFC9A7, # The ERC-165 identifier for ERC-165. 0xD9B67A26, # The ERC-165 identifier for ERC-1155. @@ -68,17 +93,22 @@ _SUPPORTED_INTERFACES: constant(bytes4[3]) = [ # @dev Stores the upper bound for batch calls. -_BATCH_SIZE: constant(uint16) = 255 +_BATCH_SIZE: constant(uint8) = 128 # @dev Stores the base URI for computing `uri`. _BASE_URI: immutable(String[80]) -# @dev Mapping from owner to operator approvals. +# @dev Returns the amount of tokens of token type +# `id` owned by an `address`. # @notice If you declare a variable as `public`, # Vyper automatically generates an `external` # getter function for the variable. +balanceOf: public(HashMap[address, HashMap[uint256, uint256]]) + + +# @dev Mapping from owner to operator approvals. isApprovedForAll: public(HashMap[address, HashMap[address, bool]]) @@ -91,14 +121,6 @@ total_supply: public(HashMap[uint256, uint256]) is_minter: public(HashMap[address, bool]) -# @dev Returns address of the current owner. -owner: public(address) - - -# @dev Mapping from token ID to owner balance. -_balances: HashMap[uint256, HashMap[address, uint256]] - - # @dev Mapping from token ID to token URI. # @notice Since the Vyper design requires # strings of fixed size, we arbitrarily set @@ -110,54 +132,6 @@ _balances: HashMap[uint256, HashMap[address, uint256]] _token_uris: HashMap[uint256, String[432]] -# @dev Emitted when `amount` tokens of token type -# `id` are transferred from `owner` to `to` by -# `operator`. -event TransferSingle: - operator: indexed(address) - owner: indexed(address) - to: indexed(address) - id: uint256 - amount: uint256 - - -# @dev Equivalent to multiple `TransferSingle` events, -# where `operator`, `owner`, and `to` are the same -# for all transfers. -event TransferBatch: - operator: indexed(address) - owner: indexed(address) - to: indexed(address) - ids: DynArray[uint256, _BATCH_SIZE] - amounts: DynArray[uint256, _BATCH_SIZE] - - -# @dev Emitted when `owner` grants or revokes permission -# to `operator` to transfer their tokens, according to -# `approved`. -event ApprovalForAll: - owner: indexed(address) - operator: indexed(address) - approved: bool - - -# @dev Emitted when the Uniform Resource Identifier (URI) -# for token type `id` changes to `value`, if it is a -# non-programmatic URI. Note that if an `URI` event was -# emitted for `id`, the EIP-1155 standard guarantees that -# `value` will equal the value returned by `uri`. -event URI: - value: String[512] - id: indexed(uint256) - - -# @dev Emitted when the ownership is transferred -# from `previous_owner` to `new_owner`. -event OwnershipTransferred: - previous_owner: indexed(address) - new_owner: indexed(address) - - # @dev Emitted when the status of a `minter` # address is changed. event RoleMinterChanged: @@ -165,19 +139,23 @@ event RoleMinterChanged: status: bool -@external +@deploy @payable def __init__(base_uri_: String[80]): """ @dev To omit the opcodes for checking the `msg.value` in the creation-time EVM bytecode, the constructor is declared as `payable`. + @notice At initialisation time, the `owner` role will be + assigned to the `msg.sender` since we `uses` the + `ownable` module, which implements the aforementioned + logic at contract creation time. @param base_uri_ The maximum 80-character user-readable string base URI for computing `uri`. """ _BASE_URI = base_uri_ - self._transfer_ownership(msg.sender) + ownable._transfer_ownership(msg.sender) self.is_minter[msg.sender] = True log RoleMinterChanged(msg.sender, True) @@ -224,7 +202,7 @@ def safeTransferFrom(owner: address, to: address, id: uint256, amount: uint256, @param data The maximum 1,024-byte additional data with no specified format. """ - assert owner == msg.sender or self.isApprovedForAll[owner][msg.sender], "ERC1155: caller is not token owner or approved" + assert ((owner == msg.sender) or (self.isApprovedForAll[owner][msg.sender])), "erc1155: caller is not token owner or approved" self._safe_transfer_from(owner, to, id, amount, data) @@ -256,26 +234,10 @@ def safeBatchTransferFrom(owner: address, to: address, ids: DynArray[uint256, _B @param data The maximum 1,024-byte additional data with no specified format. """ - assert owner == msg.sender or self.isApprovedForAll[owner][msg.sender], "ERC1155: caller is not token owner or approved" + assert ((owner == msg.sender) or (self.isApprovedForAll[owner][msg.sender])), "erc1155: caller is not token owner or approved" self._safe_batch_transfer_from(owner, to, ids, amounts, data) -@external -@view -def balanceOf(owner: address, id: uint256) -> uint256: - """ - @dev Returns the amount of tokens of token type - `id` owned by `owner`. - @notice Note that `owner` cannot be the zero - address. - @param owner The 20-byte owner address. - @param id The 32-byte identifier of the token. - @return uint256 The 32-byte token amount owned - by `owner`. - """ - return self._balance_of(owner, id) - - @external @view def balanceOfBatch(owners: DynArray[address, _BATCH_SIZE], ids: DynArray[uint256, _BATCH_SIZE]) -> DynArray[uint256, _BATCH_SIZE]: @@ -288,11 +250,11 @@ def balanceOfBatch(owners: DynArray[address, _BATCH_SIZE], ids: DynArray[uint256 @return DynArray The 32-byte array of token amounts owned by `owners`. """ - assert len(owners) == len(ids), "ERC1155: owners and ids length mismatch" + assert len(owners) == len(ids), "erc1155: owners and ids length mismatch" batch_balances: DynArray[uint256, _BATCH_SIZE] = [] idx: uint256 = empty(uint256) - for owner in owners: - batch_balances.append(self._balance_of(owner, ids[idx])) + for owner: address in owners: + batch_balances.append(self.balanceOf[owner][ids[idx]]) # The following line cannot overflow because we have # limited the dynamic array `owners` by the `constant` # parameter `_BATCH_SIZE`, which is bounded by the @@ -347,7 +309,7 @@ def set_uri(id: uint256, token_uri: String[432]): @param token_uri The maximum 432-character user-readable string URI for computing `uri`. """ - assert self.is_minter[msg.sender], "AccessControl: access is denied" + assert self.is_minter[msg.sender], "erc1155: access is denied" self._set_uri(id, token_uri) @@ -376,7 +338,7 @@ def burn(owner: address, id: uint256, amount: uint256): @param id The 32-byte identifier of the token. @param amount The 32-byte token amount to be destroyed. """ - assert owner == msg.sender or self.isApprovedForAll[owner][msg.sender], "ERC1155: caller is not token owner or approved" + assert ((owner == msg.sender) or (self.isApprovedForAll[owner][msg.sender])), "erc1155: caller is not token owner or approved" self._burn(owner, id, amount) @@ -394,7 +356,7 @@ def burn_batch(owner: address, ids: DynArray[uint256, _BATCH_SIZE], amounts: Dyn being destroyed. Note that the order and length must match the 32-byte `ids` array. """ - assert owner == msg.sender or self.isApprovedForAll[owner][msg.sender], "ERC1155: caller is not token owner or approved" + assert ((owner == msg.sender) or (self.isApprovedForAll[owner][msg.sender])), "erc1155: caller is not token owner or approved" self._burn_batch(owner, ids, amounts) @@ -414,7 +376,7 @@ def safe_mint(owner: address, id: uint256, amount: uint256, data: Bytes[1_024]): @param data The maximum 1,024-byte additional data with no specified format. """ - assert self.is_minter[msg.sender], "AccessControl: access is denied" + assert self.is_minter[msg.sender], "erc1155: access is denied" self._safe_mint(owner, id, amount, data) @@ -436,7 +398,7 @@ def safe_mint_batch(owner: address, ids: DynArray[uint256, _BATCH_SIZE], amounts @param data The maximum 1,024-byte additional data with no specified format. """ - assert self.is_minter[msg.sender], "AccessControl: access is denied" + assert self.is_minter[msg.sender], "erc1155: access is denied" self._safe_mint_batch(owner, ids, amounts, data) @@ -452,11 +414,11 @@ def set_minter(minter: address, status: bool): @param minter The 20-byte minter address. @param status The Boolean variable that sets the status. """ - self._check_owner() - assert minter != empty(address), "AccessControl: minter is the zero address" - # We ensured in the previous step `self._check_owner()` + ownable._check_owner() + assert minter != empty(address), "erc1155: minter is the zero address" + # We ensured in the previous step `ownable._check_owner` # that `msg.sender` is the `owner`. - assert minter != msg.sender, "AccessControl: minter is owner address" + assert minter != msg.sender, "erc1155: minter is owner address" self.is_minter[minter] = status log RoleMinterChanged(minter, status) @@ -475,13 +437,13 @@ def transfer_ownership(new_owner: address): the minter role to `new_owner` accordingly. @param new_owner The 20-byte address of the new owner. """ - self._check_owner() - assert new_owner != empty(address), "Ownable: new owner is the zero address" + ownable._check_owner() + assert new_owner != empty(address), "erc1155: new owner is the zero address" self.is_minter[msg.sender] = False log RoleMinterChanged(msg.sender, False) - self._transfer_ownership(new_owner) + ownable._transfer_ownership(new_owner) self.is_minter[new_owner] = True log RoleMinterChanged(new_owner, True) @@ -503,10 +465,10 @@ def renounce_ownership(): minter addresses first via `set_minter` before calling `renounce_ownership`. """ - self._check_owner() + ownable._check_owner() self.is_minter[msg.sender] = False log RoleMinterChanged(msg.sender, False) - self._transfer_ownership(empty(address)) + ownable._transfer_ownership(empty(address)) @internal @@ -519,9 +481,9 @@ def _set_approval_for_all(owner: address, operator: address, approved: bool): @param approved The Boolean variable that sets the approval status. """ - assert owner != operator, "ERC1155: setting approval status for self" + assert owner != operator, "erc1155: setting approval status for self" self.isApprovedForAll[owner][operator] = approved - log ApprovalForAll(owner, operator, approved) + log IERC1155.ApprovalForAll(owner, operator, approved) @internal @@ -550,22 +512,22 @@ def _safe_transfer_from(owner: address, to: address, id: uint256, amount: uint25 @param data The maximum 1,024-byte additional data with no specified format. """ - assert to != empty(address), "ERC1155: transfer to the zero address" + assert to != empty(address), "erc1155: transfer to the zero address" self._before_token_transfer(owner, to, self._as_singleton_array(id), self._as_singleton_array(amount), data) - owner_balance: uint256 = self._balances[id][owner] - assert owner_balance >= amount, "ERC1155: insufficient balance for transfer" - self._balances[id][owner] = unsafe_sub(owner_balance, amount) + owner_balance: uint256 = self.balanceOf[owner][id] + assert owner_balance >= amount, "erc1155: insufficient balance for transfer" + self.balanceOf[owner][id] = unsafe_sub(owner_balance, amount) # In the next line, an overflow is not possible # due to an arithmetic check of the entire token # supply in the functions `_safe_mint` and `_safe_mint_batch`. - self._balances[id][to] = unsafe_add(self._balances[id][to], amount) - log TransferSingle(msg.sender, owner, to, id, amount) + self.balanceOf[to][id] = unsafe_add(self.balanceOf[to][id], amount) + log IERC1155.TransferSingle(msg.sender, owner, to, id, amount) self._after_token_transfer(owner, to, self._as_singleton_array(id), self._as_singleton_array(amount), data) - assert self._check_on_erc1155_received(owner, to, id, amount, data), "ERC1155: transfer to non-ERC1155Receiver implementer" + assert self._check_on_erc1155_received(owner, to, id, amount, data), "erc1155: transfer to non-IERC1155Receiver implementer" @internal @@ -596,49 +558,32 @@ def _safe_batch_transfer_from(owner: address, to: address, ids: DynArray[uint256 @param data The maximum 1,024-byte additional data with no specified format. """ - assert len(ids) == len(amounts), "ERC1155: ids and amounts length mismatch" - assert to != empty(address), "ERC1155: transfer to the zero address" + assert len(ids) == len(amounts), "erc1155: ids and amounts length mismatch" + assert to != empty(address), "erc1155: transfer to the zero address" self._before_token_transfer(owner, to, ids, amounts, data) idx: uint256 = empty(uint256) - for id in ids: + for id: uint256 in ids: amount: uint256 = amounts[idx] - owner_balance: uint256 = self._balances[id][owner] - assert owner_balance >= amount, "ERC1155: insufficient balance for transfer" - self._balances[id][owner] = unsafe_sub(owner_balance, amount) + owner_balance: uint256 = self.balanceOf[owner][id] + assert owner_balance >= amount, "erc1155: insufficient balance for transfer" + self.balanceOf[owner][id] = unsafe_sub(owner_balance, amount) # In the next line, an overflow is not possible # due to an arithmetic check of the entire token # supply in the functions `_safe_mint` and `_safe_mint_batch`. - self._balances[id][to] = unsafe_add(self._balances[id][to], amount) + self.balanceOf[to][id] = unsafe_add(self.balanceOf[to][id], amount) # The following line cannot overflow because we have # limited the dynamic array `ids` by the `constant` # parameter `_BATCH_SIZE`, which is bounded by the # maximum value of `uint16`. idx = unsafe_add(idx, 1) - log TransferBatch(msg.sender, owner, to, ids, amounts) + log IERC1155.TransferBatch(msg.sender, owner, to, ids, amounts) self._after_token_transfer(owner, to, ids, amounts, data) - assert self._check_on_erc1155_batch_received(owner, to, ids, amounts, data), "ERC1155: transfer to non-ERC1155Receiver implementer" - - -@internal -@view -def _balance_of(owner: address, id: uint256) -> uint256: - """ - @dev An `internal` helper function that returns the - amount of tokens of token type `id` owned by `owner`. - @notice Note that `owner` cannot be the zero - address. - @param owner The 20-byte owner address. - @param id The 32-byte identifier of the token. - @return uint256 The 32-byte token amount owned - by `owner`. - """ - assert owner != empty(address), "ERC1155: address zero is not a valid owner" - return self._balances[id][owner] + assert self._check_on_erc1155_batch_received(owner, to, ids, amounts, data), "erc1155: transfer to non-IERC1155Receiver implementer" @internal @@ -665,19 +610,19 @@ def _safe_mint(owner: address, id: uint256, amount: uint256, data: Bytes[1_024]) @param data The maximum 1,024-byte additional data with no specified format. """ - assert owner != empty(address), "ERC1155: mint to the zero address" + assert owner != empty(address), "erc1155: mint to the zero address" self._before_token_transfer(empty(address), owner, self._as_singleton_array(id), self._as_singleton_array(amount), data) # In the next line, an overflow is not possible # due to an arithmetic check of the entire token # supply in the function `_before_token_transfer`. - self._balances[id][owner] = unsafe_add(self._balances[id][owner], amount) - log TransferSingle(msg.sender, empty(address), owner, id, amount) + self.balanceOf[owner][id] = unsafe_add(self.balanceOf[owner][id], amount) + log IERC1155.TransferSingle(msg.sender, empty(address), owner, id, amount) self._after_token_transfer(empty(address), owner, self._as_singleton_array(id), self._as_singleton_array(amount), data) - assert self._check_on_erc1155_received(empty(address), owner, id, amount, data), "ERC1155: mint to non-ERC1155Receiver implementer" + assert self._check_on_erc1155_received(empty(address), owner, id, amount, data), "erc1155: mint to non-IERC1155Receiver implementer" @internal @@ -706,28 +651,28 @@ def _safe_mint_batch(owner: address, ids: DynArray[uint256, _BATCH_SIZE], amount @param data The maximum 1,024-byte additional data with no specified format. """ - assert len(ids) == len(amounts), "ERC1155: ids and amounts length mismatch" - assert owner != empty(address), "ERC1155: mint to the zero address" + assert len(ids) == len(amounts), "erc1155: ids and amounts length mismatch" + assert owner != empty(address), "erc1155: mint to the zero address" self._before_token_transfer(empty(address), owner, ids, amounts, data) idx: uint256 = empty(uint256) - for id in ids: + for id: uint256 in ids: # In the next line, an overflow is not possible # due to an arithmetic check of the entire token # supply in the function `_before_token_transfer`. - self._balances[id][owner] = unsafe_add(self._balances[id][owner], amounts[idx]) + self.balanceOf[owner][id] = unsafe_add(self.balanceOf[owner][id], amounts[idx]) # The following line cannot overflow because we have # limited the dynamic array `ids` by the `constant` # parameter `_BATCH_SIZE`, which is bounded by the # maximum value of `uint16`. idx = unsafe_add(idx, 1) - log TransferBatch(msg.sender, empty(address), owner, ids, amounts) + log IERC1155.TransferBatch(msg.sender, empty(address), owner, ids, amounts) self._after_token_transfer(empty(address), owner, ids, amounts, data) - assert self._check_on_erc1155_batch_received(empty(address), owner, ids, amounts, data), "ERC1155: transfer to non-ERC1155Receiver implementer" + assert self._check_on_erc1155_batch_received(empty(address), owner, ids, amounts, data), "erc1155: transfer to non-IERC1155Receiver implementer" @internal @@ -752,15 +697,13 @@ def _uri(id: uint256) -> String[512]: # If there is no base URI, return the token URI. if (base_uri_length == empty(uint256)): return token_uri - # If both are set, concatenate the base URI # and token URI. - if (len(token_uri) != empty(uint256)): + elif (len(token_uri) != empty(uint256)): return concat(_BASE_URI, token_uri) - # If there is no token URI but a base URI, # concatenate the base URI and token ID. - if (base_uri_length != empty(uint256)): + elif (base_uri_length != empty(uint256)): # Please note that for projects where the # substring `{id}` is present in the URI # and this URI is to be set as `_BASE_URI`, @@ -768,8 +711,8 @@ def _uri(id: uint256) -> String[512]: # concatenation and simply return `_BASE_URI` # for easier off-chain handling. return concat(_BASE_URI, uint2str(id)) - else: - return "" + + return "" @internal @@ -786,7 +729,7 @@ def _set_uri(id: uint256, token_uri: String[432]): string URI for computing `uri`. """ self._token_uris[id] = token_uri - log URI(self._uri(id), id) + log IERC1155.URI(self._uri(id), id) @internal @@ -801,14 +744,14 @@ def _burn(owner: address, id: uint256, amount: uint256): @param id The 32-byte identifier of the token. @param amount The 32-byte token amount to be destroyed. """ - assert owner != empty(address), "ERC1155: burn from the zero address" + assert owner != empty(address), "erc1155: burn from the zero address" self._before_token_transfer(owner, empty(address), self._as_singleton_array(id), self._as_singleton_array(amount), b"") - owner_balance: uint256 = self._balances[id][owner] - assert owner_balance >= amount, "ERC1155: burn amount exceeds balance" - self._balances[id][owner] = unsafe_sub(owner_balance, amount) - log TransferSingle(msg.sender, owner, empty(address), id, amount) + owner_balance: uint256 = self.balanceOf[owner][id] + assert owner_balance >= amount, "erc1155: burn amount exceeds balance" + self.balanceOf[owner][id] = unsafe_sub(owner_balance, amount) + log IERC1155.TransferSingle(msg.sender, owner, empty(address), id, amount) self._after_token_transfer(owner, empty(address), self._as_singleton_array(id), self._as_singleton_array(amount), b"") @@ -827,24 +770,24 @@ def _burn_batch(owner: address, ids: DynArray[uint256, _BATCH_SIZE], amounts: Dy being destroyed. Note that the order and length must match the 32-byte `ids` array. """ - assert len(ids) == len(amounts), "ERC1155: ids and amounts length mismatch" - assert owner != empty(address), "ERC1155: burn from the zero address" + assert len(ids) == len(amounts), "erc1155: ids and amounts length mismatch" + assert owner != empty(address), "erc1155: burn from the zero address" self._before_token_transfer(owner, empty(address), ids, amounts, b"") idx: uint256 = empty(uint256) - for id in ids: + for id: uint256 in ids: amount: uint256 = amounts[idx] - owner_balance: uint256 = self._balances[id][owner] - assert owner_balance >= amount, "ERC1155: burn amount exceeds balance" - self._balances[id][owner] = unsafe_sub(owner_balance, amount) + owner_balance: uint256 = self.balanceOf[owner][id] + assert owner_balance >= amount, "erc1155: burn amount exceeds balance" + self.balanceOf[owner][id] = unsafe_sub(owner_balance, amount) # The following line cannot overflow because we have # limited the dynamic array `ids` by the `constant` # parameter `_BATCH_SIZE`, which is bounded by the # maximum value of `uint16`. idx = unsafe_add(idx, 1) - log TransferBatch(msg.sender, owner, empty(address), ids, amounts) + log IERC1155.TransferBatch(msg.sender, owner, empty(address), ids, amounts) self._after_token_transfer(owner, empty(address), ids, amounts, b"") @@ -868,13 +811,13 @@ def _check_on_erc1155_received(owner: address, to: address, id: uint256, amount: """ # Contract case. if (to.is_contract): - return_value: bytes4 = IERC1155Receiver(to).onERC1155Received(msg.sender, owner, id, amount, data) + return_value: bytes4 = extcall IERC1155Receiver(to).onERC1155Received(msg.sender, owner, id, amount, data) assert return_value == method_id("onERC1155Received(address,address,uint256,uint256,bytes)", output_type=bytes4),\ - "ERC1155: transfer to non-ERC1155Receiver implementer" + "erc1155: transfer to non-IERC1155Receiver implementer" return True + # EOA case. - else: - return True + return True @internal @@ -897,13 +840,13 @@ def _check_on_erc1155_batch_received(owner: address, to: address, ids: DynArray[ """ # Contract case. if (to.is_contract): - return_value: bytes4 = IERC1155Receiver(to).onERC1155BatchReceived(msg.sender, owner, ids, amounts, data) + return_value: bytes4 = extcall IERC1155Receiver(to).onERC1155BatchReceived(msg.sender, owner, ids, amounts, data) assert return_value == method_id("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)", output_type=bytes4),\ - "ERC1155: transfer to non-ERC1155Receiver implementer" + "erc1155: transfer to non-IERC1155Receiver implementer" return True + # EOA case. - else: - return True + return True @internal @@ -941,7 +884,7 @@ def _before_token_transfer(owner: address, to: address, ids: DynArray[uint256, _ """ if (owner == empty(address)): idx: uint256 = empty(uint256) - for id in ids: + for id: uint256 in ids: # The following line uses intentionally checked arithmetic # to ensure that the total supply for each token type `id` # never overflows. @@ -954,10 +897,10 @@ def _before_token_transfer(owner: address, to: address, ids: DynArray[uint256, _ if (to == empty(address)): idx: uint256 = empty(uint256) - for id in ids: + for id: uint256 in ids: amount: uint256 = amounts[idx] supply: uint256 = self.total_supply[id] - assert supply >= amount, "ERC1155: burn amount exceeds total_supply" + assert supply >= amount, "erc1155: burn amount exceeds total_supply" self.total_supply[id] = unsafe_sub(supply, amount) # The following line cannot overflow because we have # limited the dynamic array `ids` by the `constant` @@ -1012,25 +955,3 @@ def _as_singleton_array(element: uint256) -> DynArray[uint256, 1]: @return DynArray The array of length 1 containing `element`. """ return [element] - - -@internal -def _check_owner(): - """ - @dev Sourced from {Ownable-_check_owner}. - @notice See {Ownable-_check_owner} for - the function docstring. - """ - assert msg.sender == self.owner, "Ownable: caller is not the owner" - - -@internal -def _transfer_ownership(new_owner: address): - """ - @dev Sourced from {Ownable-_transfer_ownership}. - @notice See {Ownable-_transfer_ownership} for - the function docstring. - """ - old_owner: address = self.owner - self.owner = new_owner - log OwnershipTransferred(old_owner, new_owner) diff --git a/src/snekmate/tokens/ERC20.vy b/src/snekmate/tokens/erc20.vy similarity index 66% rename from src/snekmate/tokens/ERC20.vy rename to src/snekmate/tokens/erc20.vy index 1af5e07e..137f1a7c 100644 --- a/src/snekmate/tokens/ERC20.vy +++ b/src/snekmate/tokens/erc20.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Modern and Gas-Efficient ERC-20 + EIP-2612 Implementation -@custom:contract-name ERC20 +@custom:contract-name erc20 @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions implement the ERC-20 @@ -39,7 +39,7 @@ https://github.com/ApeAcademy/ERC20/blob/main/%7B%7Bcookiecutter.project_name%7D%7D/contracts/Token.vy. @custom:security This ERC-20 implementation allows the commonly known address poisoning attack, where `transferFrom` instructions - are executed from arbitrary addresses with an `amount` of 0. + are executed from arbitrary addresses with an `amount` of `0`. However, this poisoning attack is not an on-chain vulnerability. All assets are safe. It is an off-chain log interpretation issue. The main reason why we do not disallow address poisonig is that @@ -51,16 +51,16 @@ """ -# @dev We import and implement the `ERC20` interface, +# @dev We import and implement the `IERC20` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC20 -implements: ERC20 +from ethereum.ercs import IERC20 +implements: IERC20 -# @dev We import and implement the `ERC20Detailed` interface, +# @dev We import and implement the `IERC20Detailed` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC20Detailed -implements: ERC20Detailed +from ethereum.ercs import IERC20Detailed +implements: IERC20Detailed # @dev We import and implement the `IERC20Permit` @@ -76,25 +76,41 @@ from ..utils.interfaces import IERC5267 implements: IERC5267 -# @dev Returns the decimals places of the token. -# The default value is 18. -# @notice If you declare a variable as `public`, -# Vyper automatically generates an `external` -# getter function for the variable. Furthermore, -# to preserve consistency with the interface for -# the optional metadata functions of the ERC-20 -# standard, we use lower case letters for the -# `immutable` and `constant` variables `name`, -# `symbol`, and `decimals`. -decimals: public(constant(uint8)) = 18 +# @dev We import and use the `ownable` module. +from ..auth import ownable +uses: ownable -# @dev Constant used as part of the ECDSA recovery function. -_MALLEABILITY_THRESHOLD: constant(bytes32) = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 +# @dev We import the `ecdsa` module. +# @notice Please note that the `ecdsa` module +# is stateless and therefore does not require +# the `uses` keyword for usage. +from ..utils import ecdsa -# @dev The 32-byte type hash for the EIP-712 domain separator. -_TYPE_HASH: constant(bytes32) = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") +# @dev We import and use the `eip712_domain_separator` module. +from ..utils import eip712_domain_separator +initializes: eip712_domain_separator + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) the `external` getter +# function `owner` from the `ownable` module as well as the +# function `eip712Domain` from the `eip712_domain_separator` +# module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ( + # @notice This ERC-20 implementation includes the `transfer_ownership` + # and `renounce_ownership` functions, which incorporate + # the additional built-in `is_minter` role logic and are + # therefore not exported from the `ownable` module. + ownable.owner, + eip712_domain_separator.eip712Domain, +) # @dev The 32-byte type hash of the `permit` function. @@ -102,37 +118,27 @@ _PERMIT_TYPE_HASH: constant(bytes32) = keccak256("Permit(address owner,address s # @dev Returns the name of the token. -# @notice See comment on lower case letters -# above at `decimals`. +# @notice If you declare a variable as `public`, +# Vyper automatically generates an `external` +# getter function for the variable. Furthermore, +# to preserve consistency with the interface for +# the optional metadata functions of the ERC-20 +# standard, we use lower case letters for the +# `immutable` variables `name`, `symbol`, and +# `decimals`. name: public(immutable(String[25])) # @dev Returns the symbol of the token. # @notice See comment on lower case letters -# above at `decimals`. +# above at `name`. symbol: public(immutable(String[5])) -# @dev Caches the domain separator as an `immutable` -# value, but also stores the corresponding chain ID -# to invalidate the cached domain separator if the -# chain ID changes. -_CACHED_DOMAIN_SEPARATOR: immutable(bytes32) -_CACHED_CHAIN_ID: immutable(uint256) - - -# @dev Caches `self` to `immutable` storage to avoid -# potential issues if a vanilla contract is used in -# a `delegatecall` context. -_CACHED_SELF: immutable(address) - - -# @dev `immutable` variables to store the (hashed) -# name and (hashed) version during contract creation. -_NAME: immutable(String[50]) -_HASHED_NAME: immutable(bytes32) -_VERSION: immutable(String[20]) -_HASHED_VERSION: immutable(bytes32) +# @dev Returns the decimal places of the token. +# @notice See comment on lower case letters +# above at `name`. +decimals: public(immutable(uint8)) # @dev Returns the amount of tokens owned by an `address`. @@ -151,10 +157,6 @@ allowance: public(HashMap[address, HashMap[address, uint256]]) totalSupply: public(uint256) -# @dev Returns the address of the current owner. -owner: public(address) - - # @dev Returns `True` if an `address` has been # granted the minter role. is_minter: public(HashMap[address, bool]) @@ -165,37 +167,6 @@ is_minter: public(HashMap[address, bool]) nonces: public(HashMap[address, uint256]) -# @dev Emitted when `amount` tokens are moved -# from one account (`owner`) to another (`to`). -# Note that the parameter `amount` may be zero. -event Transfer: - owner: indexed(address) - to: indexed(address) - amount: uint256 - - -# @dev Emitted when the allowance of a `spender` -# for an `owner` is set by a call to `approve`. -# The parameter `amount` is the new allowance. -event Approval: - owner: indexed(address) - spender: indexed(address) - amount: uint256 - - -# @dev May be emitted to signal that the domain could -# have changed. -event EIP712DomainChanged: - pass - - -# @dev Emitted when the ownership is transferred -# from `previous_owner` to `new_owner`. -event OwnershipTransferred: - previous_owner: indexed(address) - new_owner: indexed(address) - - # @dev Emitted when the status of a `minter` # address is changed. event RoleMinterChanged: @@ -203,21 +174,22 @@ event RoleMinterChanged: status: bool -@external +@deploy @payable -def __init__(name_: String[25], symbol_: String[5], initial_supply_: uint256, name_eip712_: String[50], version_eip712_: String[20]): +def __init__(name_: String[25], symbol_: String[5], decimals_: uint8, name_eip712_: String[50], version_eip712_: String[20]): """ @dev To omit the opcodes for checking the `msg.value` in the creation-time EVM bytecode, the constructor is declared as `payable`. - @notice The initial supply of the token as well - as the `owner` role will be assigned to - the `msg.sender`. + @notice At initialisation time, the `owner` role will be + assigned to the `msg.sender` since we `uses` the + `ownable` module, which implements the aforementioned + logic at contract creation time. @param name_ The maximum 25-character user-readable string name of the token. @param symbol_ The maximum 5-character user-readable string symbol of the token. - @param initial_supply_ The initial supply of the token. + @param decimals_ The 1-byte decimal places of the token. @param name_eip712_ The maximum 50-character user-readable string name of the signing domain, i.e. the name of the dApp or protocol. @@ -225,28 +197,15 @@ def __init__(name_: String[25], symbol_: String[5], initial_supply_: uint256, na main version of the signing domain. Signatures from different versions are not compatible. """ - initial_supply: uint256 = initial_supply_ * 10 ** convert(decimals, uint256) name = name_ symbol = symbol_ + decimals = decimals_ - self._transfer_ownership(msg.sender) + ownable._transfer_ownership(msg.sender) self.is_minter[msg.sender] = True log RoleMinterChanged(msg.sender, True) - if (initial_supply != empty(uint256)): - self._before_token_transfer(empty(address), msg.sender, initial_supply) - self.totalSupply = initial_supply - self.balanceOf[msg.sender] = initial_supply - log Transfer(empty(address), msg.sender, initial_supply) - self._after_token_transfer(empty(address), msg.sender, initial_supply) - - _NAME = name_eip712_ - _VERSION = version_eip712_ - _HASHED_NAME = keccak256(name_eip712_) - _HASHED_VERSION = keccak256(version_eip712_) - _CACHED_DOMAIN_SEPARATOR = self._build_domain_separator() - _CACHED_CHAIN_ID = chain.id - _CACHED_SELF = self + eip712_domain_separator.__init__(name_eip712_, version_eip712_) @external @@ -356,9 +315,10 @@ def mint(owner: address, amount: uint256): @dev Creates `amount` tokens and assigns them to `owner`. @notice Only authorised minters can access this function. Note that `owner` cannot be the zero address. + @param owner The 20-byte owner address. @param amount The 32-byte token amount to be created. """ - assert self.is_minter[msg.sender], "AccessControl: access is denied" + assert self.is_minter[msg.sender], "erc20: access is denied" self._mint(owner, amount) @@ -374,11 +334,11 @@ def set_minter(minter: address, status: bool): @param minter The 20-byte minter address. @param status The Boolean variable that sets the status. """ - self._check_owner() - assert minter != empty(address), "AccessControl: minter is the zero address" - # We ensured in the previous step `self._check_owner()` + ownable._check_owner() + assert minter != empty(address), "erc20: minter is the zero address" + # We ensured in the previous step `ownable._check_owner` # that `msg.sender` is the `owner`. - assert minter != msg.sender, "AccessControl: minter is owner address" + assert minter != msg.sender, "erc20: minter is owner address" self.is_minter[minter] = status log RoleMinterChanged(minter, status) @@ -405,16 +365,16 @@ def permit(owner: address, spender: address, amount: uint256, deadline: uint256, @param r The secp256k1 32-byte signature parameter `r`. @param s The secp256k1 32-byte signature parameter `s`. """ - assert block.timestamp <= deadline, "ERC20Permit: expired deadline" + assert block.timestamp <= deadline, "erc20: expired deadline" current_nonce: uint256 = self.nonces[owner] self.nonces[owner] = unsafe_add(current_nonce, 1) struct_hash: bytes32 = keccak256(_abi_encode(_PERMIT_TYPE_HASH, owner, spender, amount, current_nonce, deadline)) - hash: bytes32 = self._hash_typed_data_v4(struct_hash) + hash: bytes32 = eip712_domain_separator._hash_typed_data_v4(struct_hash) - signer: address = self._recover_vrs(hash, convert(v, uint256), convert(r, uint256), convert(s, uint256)) - assert signer == owner, "ERC20Permit: invalid signature" + signer: address = ecdsa._recover_vrs(hash, convert(v, uint256), convert(r, uint256), convert(s, uint256)) + assert signer == owner, "erc20: invalid signature" self._approve(owner, spender, amount) @@ -426,33 +386,7 @@ def DOMAIN_SEPARATOR() -> bytes32: @dev Returns the domain separator for the current chain. @return bytes32 The 32-byte domain separator. """ - return self._domain_separator_v4() - - -@external -@view -def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 128]): - """ - @dev Returns the fields and values that describe the domain - separator used by this contract for EIP-712 signatures. - @notice The bits in the 1-byte bit map are read from the least - significant to the most significant, and fields are indexed - in the order that is specified by EIP-712, identical to the - order in which they are listed in the function type. - @return bytes1 The 1-byte bit map where bit `i` is set to 1 - if and only if domain field `i` is present (`0 ≤ i ≤ 4`). - @return String The maximum 50-character user-readable string name - of the signing domain, i.e. the name of the dApp or protocol. - @return String The maximum 20-character current main version of - the signing domain. Signatures from different versions are - not compatible. - @return uint256 The 32-byte EIP-155 chain ID. - @return address The 20-byte address of the verifying contract. - @return bytes32 The 32-byte disambiguation salt for the protocol. - @return DynArray The 32-byte array of EIP-712 extensions. - """ - # Note that `\x0f` equals `01111`. - return (convert(b"\x0f", bytes1), _NAME, _VERSION, chain.id, self, empty(bytes32), empty(DynArray[uint256, 128])) + return eip712_domain_separator._domain_separator_v4() @external @@ -469,13 +403,13 @@ def transfer_ownership(new_owner: address): the minter role to `new_owner` accordingly. @param new_owner The 20-byte address of the new owner. """ - self._check_owner() - assert new_owner != empty(address), "Ownable: new owner is the zero address" + ownable._check_owner() + assert new_owner != empty(address), "erc20: new owner is the zero address" self.is_minter[msg.sender] = False log RoleMinterChanged(msg.sender, False) - self._transfer_ownership(new_owner) + ownable._transfer_ownership(new_owner) self.is_minter[new_owner] = True log RoleMinterChanged(new_owner, True) @@ -497,10 +431,10 @@ def renounce_ownership(): minter addresses first via `set_minter` before calling `renounce_ownership`. """ - self._check_owner() + ownable._check_owner() self.is_minter[msg.sender] = False log RoleMinterChanged(msg.sender, False) - self._transfer_ownership(empty(address)) + ownable._transfer_ownership(empty(address)) @internal @@ -515,16 +449,16 @@ def _transfer(owner: address, to: address, amount: uint256): @param to The 20-byte receiver address. @param amount The 32-byte token amount to be transferred. """ - assert owner != empty(address), "ERC20: transfer from the zero address" - assert to != empty(address), "ERC20: transfer to the zero address" + assert owner != empty(address), "erc20: transfer from the zero address" + assert to != empty(address), "erc20: transfer to the zero address" self._before_token_transfer(owner, to, amount) owner_balanceOf: uint256 = self.balanceOf[owner] - assert owner_balanceOf >= amount, "ERC20: transfer amount exceeds balance" + assert owner_balanceOf >= amount, "erc20: transfer amount exceeds balance" self.balanceOf[owner] = unsafe_sub(owner_balanceOf, amount) self.balanceOf[to] = unsafe_add(self.balanceOf[to], amount) - log Transfer(owner, to, amount) + log IERC20.Transfer(owner, to, amount) self._after_token_transfer(owner, to, amount) @@ -541,13 +475,13 @@ def _mint(owner: address, amount: uint256): @param owner The 20-byte owner address. @param amount The 32-byte token amount to be created. """ - assert owner != empty(address), "ERC20: mint to the zero address" + assert owner != empty(address), "erc20: mint to the zero address" self._before_token_transfer(empty(address), owner, amount) self.totalSupply += amount self.balanceOf[owner] = unsafe_add(self.balanceOf[owner], amount) - log Transfer(empty(address), owner, amount) + log IERC20.Transfer(empty(address), owner, amount) self._after_token_transfer(empty(address), owner, amount) @@ -563,15 +497,15 @@ def _burn(owner: address, amount: uint256): @param owner The 20-byte owner address. @param amount The 32-byte token amount to be destroyed. """ - assert owner != empty(address), "ERC20: burn from the zero address" + assert owner != empty(address), "erc20: burn from the zero address" self._before_token_transfer(owner, empty(address), amount) account_balance: uint256 = self.balanceOf[owner] - assert account_balance >= amount, "ERC20: burn amount exceeds balance" + assert account_balance >= amount, "erc20: burn amount exceeds balance" self.balanceOf[owner] = unsafe_sub(account_balance, amount) self.totalSupply = unsafe_sub(self.totalSupply, amount) - log Transfer(owner, empty(address), amount) + log IERC20.Transfer(owner, empty(address), amount) self._after_token_transfer(owner, empty(address), amount) @@ -588,11 +522,11 @@ def _approve(owner: address, spender: address, amount: uint256): @param amount The 32-byte token amount that is allowed to be spent by the `spender`. """ - assert owner != empty(address), "ERC20: approve from the zero address" - assert spender != empty(address), "ERC20: approve to the zero address" + assert owner != empty(address), "erc20: approve from the zero address" + assert spender != empty(address), "erc20: approve to the zero address" self.allowance[owner][spender] = amount - log Approval(owner, spender, amount) + log IERC20.Approval(owner, spender, amount) @internal @@ -617,7 +551,7 @@ def _spend_allowance(owner: address, spender: address, amount: uint256): # of 0. However, this poisoning attack is not an on-chain # vulnerability. All assets are safe. It is an off-chain # log interpretation issue. - assert current_allowance >= amount, "ERC20: insufficient allowance" + assert current_allowance >= amount, "erc20: insufficient allowance" self._approve(owner, spender, unsafe_sub(current_allowance, amount)) @@ -662,99 +596,3 @@ def _after_token_transfer(owner: address, to: address, amount: uint256): been transferred. """ pass - - -@internal -def _check_owner(): - """ - @dev Sourced from {Ownable-_check_owner}. - @notice See {Ownable-_check_owner} for - the function docstring. - """ - assert msg.sender == self.owner, "Ownable: caller is not the owner" - - -@internal -def _transfer_ownership(new_owner: address): - """ - @dev Sourced from {Ownable-_transfer_ownership}. - @notice See {Ownable-_transfer_ownership} for - the function docstring. - """ - old_owner: address = self.owner - self.owner = new_owner - log OwnershipTransferred(old_owner, new_owner) - - -@internal -@view -def _domain_separator_v4() -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-domain_separator_v4}. - @notice See {EIP712DomainSeparator-domain_separator_v4} - for the function docstring. - """ - if (self == _CACHED_SELF and chain.id == _CACHED_CHAIN_ID): - return _CACHED_DOMAIN_SEPARATOR - else: - return self._build_domain_separator() - - -@internal -@view -def _build_domain_separator() -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-_build_domain_separator}. - @notice See {EIP712DomainSeparator-_build_domain_separator} - for the function docstring. - """ - return keccak256(_abi_encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, chain.id, self)) - - -@internal -@view -def _hash_typed_data_v4(struct_hash: bytes32) -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-hash_typed_data_v4}. - @notice See {EIP712DomainSeparator-hash_typed_data_v4} - for the function docstring. - """ - return self._to_typed_data_hash(self._domain_separator_v4(), struct_hash) - - -@internal -@pure -def _to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32: - """ - @dev Sourced from {ECDSA-to_typed_data_hash}. - @notice See {ECDSA-to_typed_data_hash} for the - function docstring. - """ - return keccak256(concat(b"\x19\x01", domain_separator, struct_hash)) - - -@internal -@pure -def _recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Sourced from {ECDSA-_recover_vrs}. - @notice See {ECDSA-_recover_vrs} for the - function docstring. - """ - return self._try_recover_vrs(hash, v, r, s) - - -@internal -@pure -def _try_recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Sourced from {ECDSA-_try_recover_vrs}. - @notice See {ECDSA-_try_recover_vrs} for the - function docstring. - """ - assert s <= convert(_MALLEABILITY_THRESHOLD, uint256), "ECDSA: invalid signature `s` value" - - signer: address = ecrecover(hash, v, r, s) - assert signer != empty(address), "ECDSA: invalid signature" - - return signer diff --git a/src/snekmate/tokens/ERC721.vy b/src/snekmate/tokens/erc721.vy similarity index 78% rename from src/snekmate/tokens/ERC721.vy rename to src/snekmate/tokens/erc721.vy index 716beb4d..5a8c2900 100644 --- a/src/snekmate/tokens/ERC721.vy +++ b/src/snekmate/tokens/erc721.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Modern and Gas-Efficient ERC-721 + EIP-4494 Implementation -@custom:contract-name ERC721 +@custom:contract-name erc721 @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions implement the ERC-721 @@ -46,16 +46,16 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 -# @dev We import and implement the `ERC721` interface, +# @dev We import and implement the `IERC721` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC721 -implements: ERC721 +from ethereum.ercs import IERC721 +implements: IERC721 # @dev We import and implement the `IERC721Metadata` @@ -96,10 +96,50 @@ implements: IERC5267 import interfaces.IERC721Receiver as IERC721Receiver +# @dev We import and use the `ownable` module. +from ..auth import ownable +uses: ownable + + +# @dev We import the `ecdsa` module. +# @notice Please note that the `ecdsa` module +# is stateless and therefore does not require +# the `uses` keyword for usage. +from ..utils import ecdsa + + +# @dev We import and use the `eip712_domain_separator` module. +from ..utils import eip712_domain_separator +initializes: eip712_domain_separator + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) the `external` getter +# function `owner` from the `ownable` module as well as the +# function `eip712Domain` from the `eip712_domain_separator` +# module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ( + # @notice This ERC-721 implementation includes the `transfer_ownership` + # and `renounce_ownership` functions, which incorporate + # the additional built-in `is_minter` role logic and are + # therefore not exported from the `ownable` module. + ownable.owner, + eip712_domain_separator.eip712Domain, +) + + # @dev Stores the ERC-165 interface identifier for each # imported interface. The ERC-165 interface identifier # is defined as the XOR of all function selectors in the # interface. +# @notice If you are not using the full feature set of +# this contract, please ensure you exclude the unused +# ERC-165 interface identifiers in the main contract. _SUPPORTED_INTERFACES: constant(bytes4[6]) = [ 0x01FFC9A7, # The ERC-165 identifier for ERC-165. 0x80AC58CD, # The ERC-165 identifier for ERC-721. @@ -110,14 +150,6 @@ _SUPPORTED_INTERFACES: constant(bytes4[6]) = [ ] -# @dev Constant used as part of the ECDSA recovery function. -_MALLEABILITY_THRESHOLD: constant(bytes32) = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 - - -# @dev The 32-byte type hash for the EIP-712 domain separator. -_TYPE_HASH: constant(bytes32) = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") - - # @dev The 32-byte type hash of the `permit` function. _PERMIT_TYPE_HASH: constant(bytes32) = keccak256("Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)") @@ -143,36 +175,10 @@ symbol: public(immutable(String[5])) _BASE_URI: immutable(String[80]) -# @dev Caches the domain separator as an `immutable` -# value, but also stores the corresponding chain ID -# to invalidate the cached domain separator if the -# chain ID changes. -_CACHED_DOMAIN_SEPARATOR: immutable(bytes32) -_CACHED_CHAIN_ID: immutable(uint256) - - -# @dev Caches `self` to `immutable` storage to avoid -# potential issues if a vanilla contract is used in -# a `delegatecall` context. -_CACHED_SELF: immutable(address) - - -# @dev `immutable` variables to store the (hashed) -# name and (hashed) version during contract creation. -_NAME: immutable(String[50]) -_HASHED_NAME: immutable(bytes32) -_VERSION: immutable(String[20]) -_HASHED_VERSION: immutable(bytes32) - - # @dev Mapping from owner to operator approvals. isApprovedForAll: public(HashMap[address, HashMap[address, bool]]) -# @dev Returns the address of the current owner. -owner: public(address) - - # @dev Returns `True` if an `address` has been # granted the minter role. is_minter: public(HashMap[address, bool]) @@ -230,57 +236,6 @@ _token_uris: HashMap[uint256, String[432]] _counter: uint256 -# @dev Emitted when `token_id` token is -# transferred from `owner` to `to`. -event Transfer: - owner: indexed(address) - to: indexed(address) - token_id: indexed(uint256) - - -# @dev Emitted when `owner` enables `approved` -# to manage the `token_id` token. -event Approval: - owner: indexed(address) - approved: indexed(address) - token_id: indexed(uint256) - - -# @dev Emitted when `owner` enables or disables -# (`approved`) `operator` to manage all of its -# assets. -event ApprovalForAll: - owner: indexed(address) - operator: indexed(address) - approved: bool - - -# @dev Emitted when the metadata of a token is -# changed. -event MetadataUpdate: - token_id: uint256 - - -# @dev Emitted when the metadata of a range of -# tokens is changed. -event BatchMetadataUpdate: - from_token_id: uint256 - token_id: uint256 - - -# @dev May be emitted to signal that the domain could -# have changed. -event EIP712DomainChanged: - pass - - -# @dev Emitted when the ownership is transferred -# from `previous_owner` to `new_owner`. -event OwnershipTransferred: - previous_owner: indexed(address) - new_owner: indexed(address) - - # @dev Emitted when the status of a `minter` # address is changed. event RoleMinterChanged: @@ -288,15 +243,17 @@ event RoleMinterChanged: status: bool -@external +@deploy @payable def __init__(name_: String[25], symbol_: String[5], base_uri_: String[80], name_eip712_: String[50], version_eip712_: String[20]): """ @dev To omit the opcodes for checking the `msg.value` in the creation-time EVM bytecode, the constructor is declared as `payable`. - @notice The `owner` role will be assigned to - the `msg.sender`. + @notice At initialisation time, the `owner` role will be + assigned to the `msg.sender` since we `uses` the + `ownable` module, which implements the aforementioned + logic at contract creation time. @param name_ The maximum 25-character user-readable string name of the token collection. @param symbol_ The maximum 5-character user-readable string @@ -316,17 +273,11 @@ def __init__(name_: String[25], symbol_: String[5], base_uri_: String[80], name_ symbol = symbol_ _BASE_URI = base_uri_ - self._transfer_ownership(msg.sender) + ownable._transfer_ownership(msg.sender) self.is_minter[msg.sender] = True log RoleMinterChanged(msg.sender, True) - _NAME = name_eip712_ - _VERSION = version_eip712_ - _HASHED_NAME = keccak256(name_eip712_) - _HASHED_VERSION = keccak256(version_eip712_) - _CACHED_DOMAIN_SEPARATOR = self._build_domain_separator() - _CACHED_CHAIN_ID = chain.id - _CACHED_SELF = self + eip712_domain_separator.__init__(name_eip712_, version_eip712_) @external @@ -390,8 +341,8 @@ def approve(to: address, token_id: uint256): @param token_id The 32-byte identifier of the token. """ owner: address = self._owner_of(token_id) - assert to != owner, "ERC721: approval to current owner" - assert msg.sender == owner or self.isApprovedForAll[owner][msg.sender], "ERC721: approve caller is not token owner or approved for all" + assert to != owner, "erc721: approval to current owner" + assert ((msg.sender == owner) or (self.isApprovedForAll[owner][msg.sender])), "erc721: approve caller is not token owner or approved for all" self._approve(to, token_id) @@ -449,7 +400,7 @@ def transferFrom(owner: address, to: address, token_id: uint256): @param to The 20-byte receiver address. @param token_id The 32-byte identifier of the token. """ - assert self._is_approved_or_owner(msg.sender, token_id), "ERC721: caller is not token owner or approved" + assert self._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved" self._transfer(owner, to, token_id) @@ -495,7 +446,7 @@ def safeTransferFrom(owner: address, to: address, token_id: uint256, data: Bytes with no specified format that is sent to `to`. """ - assert self._is_approved_or_owner(msg.sender, token_id), "ERC721: caller is not token owner or approved" + assert self._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved" self._safe_transfer(owner, to, token_id, data) @@ -517,18 +468,16 @@ def tokenURI(token_id: uint256) -> String[512]: # If there is no base URI, return the token URI. if (base_uri_length == empty(uint256)): return token_uri - # If both are set, concatenate the base URI # and token URI. - if (len(token_uri) != empty(uint256)): + elif (len(token_uri) != empty(uint256)): return concat(_BASE_URI, token_uri) - # If there is no token URI but a base URI, # concatenate the base URI and token ID. - if (base_uri_length != empty(uint256)): + elif (base_uri_length != empty(uint256)): return concat(_BASE_URI, uint2str(token_id)) - else: - return "" + + return "" @external @@ -550,11 +499,11 @@ def tokenByIndex(index: uint256) -> uint256: @notice Use along with `totalSupply` to enumerate all tokens. @param index The 32-byte counter (must be less - than `totalSupply()`). + than `totalSupply`). @return uint256 The 32-byte token ID at index `index`. """ - assert index < self._total_supply(), "ERC721Enumerable: global index out of bounds" + assert index < self._total_supply(), "erc721: global index out of bounds" return self._all_tokens[index] @@ -572,7 +521,7 @@ def tokenOfOwnerByIndex(owner: address, index: uint256) -> uint256: @return uint256 The 32-byte token ID owned by `owner` at index `index`. """ - assert index < self._balance_of(owner), "ERC721Enumerable: owner index out of bounds" + assert index < self._balance_of(owner), "erc721: owner index out of bounds" return self._owned_tokens[owner][index] @@ -584,7 +533,7 @@ def burn(token_id: uint256): or be an approved operator. @param token_id The 32-byte identifier of the token. """ - assert self._is_approved_or_owner(msg.sender, token_id), "ERC721: caller is not token owner or approved" + assert self._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved" self._burn(token_id) @@ -600,7 +549,7 @@ def safe_mint(owner: address, uri: String[432]): @param uri The maximum 432-character user-readable string URI for computing `tokenURI`. """ - assert self.is_minter[msg.sender], "AccessControl: access is denied" + assert self.is_minter[msg.sender], "erc721: access is denied" # New tokens will be automatically assigned an incremental ID. # The first token ID will be zero. token_id: uint256 = self._counter @@ -627,11 +576,11 @@ def set_minter(minter: address, status: bool): @param minter The 20-byte minter address. @param status The Boolean variable that sets the status. """ - self._check_owner() - assert minter != empty(address), "AccessControl: minter is the zero address" - # We ensured in the previous step `self._check_owner()` + ownable._check_owner() + assert minter != empty(address), "erc721: minter is the zero address" + # We ensured in the previous step `ownable._check_owner` # that `msg.sender` is the `owner`. - assert minter != msg.sender, "AccessControl: minter is owner address" + assert minter != msg.sender, "erc721: minter is owner address" self.is_minter[minter] = status log RoleMinterChanged(minter, status) @@ -656,17 +605,16 @@ def permit(spender: address, token_id: uint256, deadline: uint256, v: uint8, r: @param r The secp256k1 32-byte signature parameter `r`. @param s The secp256k1 32-byte signature parameter `s`. """ - assert block.timestamp <= deadline, "ERC721Permit: expired deadline" + assert block.timestamp <= deadline, "erc721: expired deadline" - owner: address = self._owner_of(token_id) current_nonce: uint256 = self.nonces[token_id] self.nonces[token_id] = unsafe_add(current_nonce, 1) struct_hash: bytes32 = keccak256(_abi_encode(_PERMIT_TYPE_HASH, spender, token_id, current_nonce, deadline)) - hash: bytes32 = self._hash_typed_data_v4(struct_hash) + hash: bytes32 = eip712_domain_separator._hash_typed_data_v4(struct_hash) - signer: address = self._recover_vrs(hash, convert(v, uint256), convert(r, uint256), convert(s, uint256)) - assert signer == owner, "ERC721Permit: invalid signature" + signer: address = ecdsa._recover_vrs(hash, convert(v, uint256), convert(r, uint256), convert(s, uint256)) + assert signer == self._owner_of(token_id), "erc721: invalid signature" self._approve(spender, token_id) @@ -678,33 +626,7 @@ def DOMAIN_SEPARATOR() -> bytes32: @dev Returns the domain separator for the current chain. @return bytes32 The 32-byte domain separator. """ - return self._domain_separator_v4() - - -@external -@view -def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 128]): - """ - @dev Returns the fields and values that describe the domain - separator used by this contract for EIP-712 signatures. - @notice The bits in the 1-byte bit map are read from the least - significant to the most significant, and fields are indexed - in the order that is specified by EIP-712, identical to the - order in which they are listed in the function type. - @return bytes1 The 1-byte bit map where bit `i` is set to 1 - if and only if domain field `i` is present (`0 ≤ i ≤ 4`). - @return String The maximum 50-character user-readable string name - of the signing domain, i.e. the name of the dApp or protocol. - @return String The maximum 20-character current main version of - the signing domain. Signatures from different versions are - not compatible. - @return uint256 The 32-byte EIP-155 chain ID. - @return address The 20-byte address of the verifying contract. - @return bytes32 The 32-byte disambiguation salt for the protocol. - @return DynArray The 32-byte array of EIP-712 extensions. - """ - # Note that `\x0f` equals `01111`. - return (convert(b"\x0f", bytes1), _NAME, _VERSION, chain.id, self, empty(bytes32), empty(DynArray[uint256, 128])) + return eip712_domain_separator._domain_separator_v4() @external @@ -721,13 +643,13 @@ def transfer_ownership(new_owner: address): the minter role to `new_owner` accordingly. @param new_owner The 20-byte address of the new owner. """ - self._check_owner() - assert new_owner != empty(address), "Ownable: new owner is the zero address" + ownable._check_owner() + assert new_owner != empty(address), "erc721: new owner is the zero address" self.is_minter[msg.sender] = False log RoleMinterChanged(msg.sender, False) - self._transfer_ownership(new_owner) + ownable._transfer_ownership(new_owner) self.is_minter[new_owner] = True log RoleMinterChanged(new_owner, True) @@ -749,10 +671,10 @@ def renounce_ownership(): minter addresses first via `set_minter` before calling `renounce_ownership`. """ - self._check_owner() + ownable._check_owner() self.is_minter[msg.sender] = False log RoleMinterChanged(msg.sender, False) - self._transfer_ownership(empty(address)) + ownable._transfer_ownership(empty(address)) @internal @@ -766,7 +688,7 @@ def _balance_of(owner: address) -> uint256: @return uint256 The 32-byte token amount owned by `owner`. """ - assert owner != empty(address), "ERC721: the zero address is not a valid owner" + assert owner != empty(address), "erc721: the zero address is not a valid owner" return self._balances[owner] @@ -781,7 +703,7 @@ def _owner_of(token_id: uint256) -> address: @return address The 20-byte owner address. """ owner: address = self._owners[token_id] - assert owner != empty(address), "ERC721: invalid token ID" + assert owner != empty(address), "erc721: invalid token ID" return owner @@ -792,7 +714,7 @@ def _require_minted(token_id: uint256): @dev Reverts if the `token_id` has not yet been minted. @param token_id The 32-byte identifier of the token. """ - assert self._exists(token_id), "ERC721: invalid token ID" + assert self._exists(token_id), "erc721: invalid token ID" @internal @@ -819,7 +741,7 @@ def _approve(to: address, token_id: uint256): @param token_id The 32-byte identifier of the token. """ self._token_approvals[token_id] = to - log Approval(self._owner_of(token_id), to, token_id) + log IERC721.Approval(self._owner_of(token_id), to, token_id) @internal @@ -845,9 +767,9 @@ def _set_approval_for_all(owner: address, operator: address, approved: bool): @param approved The Boolean variable that sets the approval status. """ - assert owner != operator, "ERC721: approve to caller" + assert owner != operator, "erc721: approve to caller" self.isApprovedForAll[owner][operator] = approved - log ApprovalForAll(owner, operator, approved) + log IERC721.ApprovalForAll(owner, operator, approved) @internal @@ -860,7 +782,7 @@ def _is_approved_or_owner(spender: address, token_id: uint256) -> bool: @param token_id The 32-byte identifier of the token. """ owner: address = self._owner_of(token_id) - return (spender == owner or self.isApprovedForAll[owner][spender] or self._get_approved(token_id) == spender) + return ((spender == owner) or (self.isApprovedForAll[owner][spender]) or (self._get_approved(token_id) == spender)) @internal @@ -886,7 +808,7 @@ def _safe_mint(owner: address, token_id: uint256, data: Bytes[1_024]): to `owner`. """ self._mint(owner, token_id) - assert self._check_on_erc721_received(empty(address), owner, token_id, data), "ERC721: transfer to non-ERC721Receiver implementer" + assert self._check_on_erc721_received(empty(address), owner, token_id, data), "erc721: transfer to non-IERC721Receiver implementer" @internal @@ -901,13 +823,13 @@ def _mint(owner: address, token_id: uint256): @param owner The 20-byte owner address. @param token_id The 32-byte identifier of the token. """ - assert owner != empty(address), "ERC721: mint to the zero address" - assert not(self._exists(token_id)), "ERC721: token already minted" + assert owner != empty(address), "erc721: mint to the zero address" + assert not(self._exists(token_id)), "erc721: token already minted" self._before_token_transfer(empty(address), owner, token_id) # Checks that the `token_id` was not minted by the # `_before_token_transfer` hook. - assert not(self._exists(token_id)), "ERC721: token already minted" + assert not(self._exists(token_id)), "erc721: token already minted" # Theoretically, the following line could overflow # if all 2**256 token IDs were minted to the same owner. @@ -916,7 +838,7 @@ def _mint(owner: address, token_id: uint256): # this is no longer even theoretically possible. self._balances[owner] = unsafe_add(self._balances[owner], 1) self._owners[token_id] = owner - log Transfer(empty(address), owner, token_id) + log IERC721.Transfer(empty(address), owner, token_id) self._after_token_transfer(empty(address), owner, token_id) @@ -954,7 +876,7 @@ def _safe_transfer(owner: address, to: address, token_id: uint256, data: Bytes[1 to `to`. """ self._transfer(owner, to, token_id) - assert self._check_on_erc721_received(owner, to, token_id, data), "ERC721: transfer to non-ERC721Receiver implementer" + assert self._check_on_erc721_received(owner, to, token_id, data), "erc721: transfer to non-IERC721Receiver implementer" @internal @@ -970,21 +892,21 @@ def _transfer(owner: address, to: address, token_id: uint256): @param to The 20-byte receiver address. @param token_id The 32-byte identifier of the token. """ - assert self._owner_of(token_id) == owner, "ERC721: transfer from incorrect owner" - assert to != empty(address), "ERC721: transfer to the zero address" - + assert self._owner_of(token_id) == owner, "erc721: transfer from incorrect owner" + assert to != empty(address), "erc721: transfer to the zero address" + self._before_token_transfer(owner, to, token_id) # Checks that the `token_id` was not transferred by the # `_before_token_transfer` hook. - assert self._owner_of(token_id) == owner, "ERC721: transfer from incorrect owner" - + assert self._owner_of(token_id) == owner, "erc721: transfer from incorrect owner" + self._token_approvals[token_id] = empty(address) # See comment why an overflow is not possible in the # following two lines above at `_mint`. self._balances[owner] = unsafe_sub(self._balances[owner], 1) self._balances[to] = unsafe_add(self._balances[to], 1) self._owners[token_id] = to - log Transfer(owner, to, token_id) + log IERC721.Transfer(owner, to, token_id) self._after_token_transfer(owner, to, token_id) @@ -998,9 +920,9 @@ def _set_token_uri(token_id: uint256, token_uri: String[432]): @param token_uri The maximum 432-character user-readable string URI for computing `tokenURI`. """ - assert self._exists(token_id), "ERC721URIStorage: URI set of nonexistent token" + assert self._exists(token_id), "erc721: URI set of nonexistent token" self._token_uris[token_id] = token_uri - log MetadataUpdate(token_id) + log IERC4906.MetadataUpdate(token_id) @internal @@ -1037,7 +959,7 @@ def _burn(token_id: uint256): # received through minting and transfer. self._balances[owner] = unsafe_sub(self._balances[owner], 1) self._owners[token_id] = empty(address) - log Transfer(owner, empty(address), token_id) + log IERC721.Transfer(owner, empty(address), token_id) self._after_token_transfer(owner, empty(address), token_id) @@ -1064,12 +986,12 @@ def _check_on_erc721_received(owner: address, to: address, token_id: uint256, da """ # Contract case. if (to.is_contract): - return_value: bytes4 = IERC721Receiver(to).onERC721Received(msg.sender, owner, token_id, data) - assert return_value == method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes4), "ERC721: transfer to non-ERC721Receiver implementer" + return_value: bytes4 = extcall IERC721Receiver(to).onERC721Received(msg.sender, owner, token_id, data) + assert return_value == method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes4), "erc721: transfer to non-IERC721Receiver implementer" return True + # EOA case. - else: - return True + return True @internal @@ -1173,7 +1095,7 @@ def _remove_token_from_owner_enumeration(owner: address, token_id:uint256): self._owned_tokens[owner][token_index] = last_token_id # Updates the moved token's index. self._owned_tokens_index[last_token_id] = token_index - + # This also deletes the contents at the # last position of the array. self._owned_tokens_index[token_id] = empty(uint256) @@ -1195,7 +1117,7 @@ def _remove_token_from_all_tokens_enumeration(token_id: uint256): # the last slot. last_token_index: uint256 = len(self._all_tokens) - 1 token_index: uint256 = self._all_tokens_index[token_id] - + # When the token to delete is the last token, # the swap operation is unnecessary. However, # since this occurs so rarely (when the last @@ -1213,99 +1135,3 @@ def _remove_token_from_all_tokens_enumeration(token_id: uint256): # last position of the array. self._all_tokens_index[token_id] = empty(uint256) self._all_tokens.pop() - - -@internal -def _check_owner(): - """ - @dev Sourced from {Ownable-_check_owner}. - @notice See {Ownable-_check_owner} for - the function docstring. - """ - assert msg.sender == self.owner, "Ownable: caller is not the owner" - - -@internal -def _transfer_ownership(new_owner: address): - """ - @dev Sourced from {Ownable-_transfer_ownership}. - @notice See {Ownable-_transfer_ownership} for - the function docstring. - """ - old_owner: address = self.owner - self.owner = new_owner - log OwnershipTransferred(old_owner, new_owner) - - -@internal -@view -def _domain_separator_v4() -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-domain_separator_v4}. - @notice See {EIP712DomainSeparator-domain_separator_v4} - for the function docstring. - """ - if (self == _CACHED_SELF and chain.id == _CACHED_CHAIN_ID): - return _CACHED_DOMAIN_SEPARATOR - else: - return self._build_domain_separator() - - -@internal -@view -def _build_domain_separator() -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-_build_domain_separator}. - @notice See {EIP712DomainSeparator-_build_domain_separator} - for the function docstring. - """ - return keccak256(_abi_encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, chain.id, self)) - - -@internal -@view -def _hash_typed_data_v4(struct_hash: bytes32) -> bytes32: - """ - @dev Sourced from {EIP712DomainSeparator-hash_typed_data_v4}. - @notice See {EIP712DomainSeparator-hash_typed_data_v4} - for the function docstring. - """ - return self._to_typed_data_hash(self._domain_separator_v4(), struct_hash) - - -@internal -@pure -def _to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32: - """ - @dev Sourced from {ECDSA-to_typed_data_hash}. - @notice See {ECDSA-to_typed_data_hash} for the - function docstring. - """ - return keccak256(concat(b"\x19\x01", domain_separator, struct_hash)) - - -@internal -@pure -def _recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Sourced from {ECDSA-_recover_vrs}. - @notice See {ECDSA-_recover_vrs} for the - function docstring. - """ - return self._try_recover_vrs(hash, v, r, s) - - -@internal -@pure -def _try_recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Sourced from {ECDSA-_try_recover_vrs}. - @notice See {ECDSA-_try_recover_vrs} for the - function docstring. - """ - assert s <= convert(_MALLEABILITY_THRESHOLD, uint256), "ECDSA: invalid signature `s` value" - - signer: address = ecrecover(hash, v, r, s) - assert signer != empty(address), "ECDSA: invalid signature" - - return signer diff --git a/src/snekmate/tokens/interfaces/IERC1155.vy b/src/snekmate/tokens/interfaces/IERC1155.vyi similarity index 95% rename from src/snekmate/tokens/interfaces/IERC1155.vy rename to src/snekmate/tokens/interfaces/IERC1155.vyi index a2f7efdf..553b6358 100644 --- a/src/snekmate/tokens/interfaces/IERC1155.vy +++ b/src/snekmate/tokens/interfaces/IERC1155.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-1155 Interface Definition @custom:contract-name IERC1155 @@ -24,10 +24,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 # @dev Emitted when `_value` tokens of token type @@ -84,7 +84,7 @@ def supportsInterface(interfaceId: bytes4) -> bool: @return bool The verification whether the contract implements the interface or not. """ - return empty(bool) + return ... @external @@ -116,7 +116,7 @@ def safeTransferFrom(_from: address, _to: address, _id: uint256, _value: uint256 @param _data The maximum 1,024-byte additional data with no specified format. """ - pass + ... @external @@ -146,7 +146,7 @@ def safeBatchTransferFrom(_from: address, _to: address, _ids: DynArray[uint256, @param _data The maximum 1,024-byte additional data with no specified format. """ - pass + ... @external @@ -155,14 +155,12 @@ def balanceOf(_owner: address, _id: uint256) -> uint256: """ @dev Returns the amount of tokens of token type `_id` owned by `_owner`. - @notice Note that `_owner` cannot be the zero - address. @param _owner The 20-byte owner address. @param _id The 32-byte identifier of the token. @return uint256 The 32-byte token amount owned by `_owner`. """ - return empty(uint256) + return ... @external @@ -177,7 +175,7 @@ def balanceOfBatch(_owners: DynArray[address, 128], _ids: DynArray[uint256, 128] @return DynArray The 32-byte array of token amounts owned by `_owners`. """ - return empty(DynArray[uint256, 128]) + return ... @external @@ -190,7 +188,7 @@ def setApprovalForAll(_operator: address, _approved: bool): @param _approved The Boolean variable that sets the approval status. """ - pass + ... @external @@ -205,4 +203,4 @@ def isApprovedForAll(_owner: address, _operator: address) -> bool: @return bool The verification whether `_operator` is approved or not. """ - return empty(bool) + return ... diff --git a/src/snekmate/tokens/interfaces/IERC1155MetadataURI.vy b/src/snekmate/tokens/interfaces/IERC1155MetadataURI.vyi similarity index 93% rename from src/snekmate/tokens/interfaces/IERC1155MetadataURI.vy rename to src/snekmate/tokens/interfaces/IERC1155MetadataURI.vyi index 506bcd2e..80785087 100644 --- a/src/snekmate/tokens/interfaces/IERC1155MetadataURI.vy +++ b/src/snekmate/tokens/interfaces/IERC1155MetadataURI.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-1155 Optional Metadata Interface Definition @custom:contract-name IERC1155MetadataURI @@ -23,10 +23,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 # @dev We import the `IERC1155` interface, which is written @@ -54,7 +54,7 @@ def supportsInterface(interfaceId: bytes4) -> bool: @return bool The verification whether the contract implements the interface or not. """ - return empty(bool) + return ... @external @@ -73,4 +73,4 @@ def uri(_id: uint256) -> String[512]: @return String The maximum 512-character user-readable string token URI of the token type `_id`. """ - return empty(String[512]) + return ... diff --git a/src/snekmate/tokens/interfaces/IERC1155Receiver.vy b/src/snekmate/tokens/interfaces/IERC1155Receiver.vyi similarity index 94% rename from src/snekmate/tokens/interfaces/IERC1155Receiver.vy rename to src/snekmate/tokens/interfaces/IERC1155Receiver.vyi index b2c493b3..bece0ca5 100644 --- a/src/snekmate/tokens/interfaces/IERC1155Receiver.vy +++ b/src/snekmate/tokens/interfaces/IERC1155Receiver.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-1155 Token Receiver Interface Definition @custom:contract-name IERC1155Receiver @@ -15,10 +15,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 @external @@ -34,7 +34,7 @@ def supportsInterface(interfaceId: bytes4) -> bool: @return bool The verification whether the contract implements the interface or not. """ - return empty(bool) + return ... @external @@ -58,7 +58,7 @@ def onERC1155Received(_operator: address, _from: address, _id: uint256, _value: with no specified format. @return bytes4 The 4-byte function selector of `onERC1155Received`. """ - return empty(bytes4) + return ... @external @@ -86,4 +86,4 @@ def onERC1155BatchReceived(_operator: address, _from: address, _ids: DynArray[ui with no specified format. @return bytes4 The 4-byte function selector of `onERC1155BatchReceived`. """ - return empty(bytes4) + return ... diff --git a/src/snekmate/tokens/interfaces/IERC20Permit.vy b/src/snekmate/tokens/interfaces/IERC20Permit.vyi similarity index 96% rename from src/snekmate/tokens/interfaces/IERC20Permit.vy rename to src/snekmate/tokens/interfaces/IERC20Permit.vyi index 44c3e8a4..d1094727 100644 --- a/src/snekmate/tokens/interfaces/IERC20Permit.vy +++ b/src/snekmate/tokens/interfaces/IERC20Permit.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-2612 Interface Definition @custom:contract-name IERC20Permit @@ -43,7 +43,7 @@ def permit(owner: address, spender: address, amount: uint256, deadline: uint256, @param r The secp256k1 32-byte signature parameter `r`. @param s The secp256k1 32-byte signature parameter `s`. """ - pass + ... @external @@ -54,7 +54,7 @@ def nonces(owner: address) -> uint256: @param owner The 20-byte owner address. @return uint256 The 32-byte owner nonce. """ - return empty(uint256) + return ... @external @@ -64,4 +64,4 @@ def DOMAIN_SEPARATOR() -> bytes32: @dev Returns the domain separator for the current chain. @return bytes32 The 32-byte domain separator. """ - return empty(bytes32) + return ... diff --git a/src/snekmate/tokens/interfaces/IERC4906.vy b/src/snekmate/tokens/interfaces/IERC4906.vyi similarity index 80% rename from src/snekmate/tokens/interfaces/IERC4906.vy rename to src/snekmate/tokens/interfaces/IERC4906.vyi index 56d46c71..365d5b8a 100644 --- a/src/snekmate/tokens/interfaces/IERC4906.vy +++ b/src/snekmate/tokens/interfaces/IERC4906.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-4906 Interface Definition @custom:contract-name IERC4906 @@ -15,22 +15,22 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 -# @dev We import the `ERC721` interface, which is a built-in +# @dev We import the `IERC721` interface, which is a built-in # interface of the Vyper compiler, to highlight the association -# of the custom `IERC4906` interface with the built-in `ERC721` +# of the custom `IERC4906` interface with the built-in `IERC721` # interface. # @notice The interface `IERC4906` must be used in conjunction -# with the built-in interface `ERC721` to be EIP-721 compatible. +# with the built-in interface `IERC721` to be EIP-721 compatible. # If you want to use this interface as a stand-alone interface, -# you must add `implements: ERC721` to this interface and implement +# you must add `implements: IERC721` to this interface and implement # all required events and functions accordingly. -from vyper.interfaces import ERC721 +from ethereum.ercs import IERC721 # @dev Emitted when the metadata of a token is changed. @@ -63,4 +63,4 @@ def supportsInterface(interfaceId: bytes4) -> bool: @return bool The verification whether the contract implements the interface or not. """ - return empty(bool) + return ... diff --git a/src/snekmate/tokens/interfaces/IERC721Enumerable.vy b/src/snekmate/tokens/interfaces/IERC721Enumerable.vyi similarity index 83% rename from src/snekmate/tokens/interfaces/IERC721Enumerable.vy rename to src/snekmate/tokens/interfaces/IERC721Enumerable.vyi index c6b780ef..71277e8e 100644 --- a/src/snekmate/tokens/interfaces/IERC721Enumerable.vy +++ b/src/snekmate/tokens/interfaces/IERC721Enumerable.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-721 Optional Enumeration Interface Definition @custom:contract-name IERC721Enumerable @@ -15,22 +15,22 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 -# @dev We import the `ERC721` interface, which is a built-in +# @dev We import the `IERC721` interface, which is a built-in # interface of the Vyper compiler, to highlight the association # of the custom `IERC721Enumerable` interface with the built-in -# `ERC721` interface. +# `IERC721` interface. # @notice The interface `IERC721Enumerable` must be used in conjunction -# with the built-in interface `ERC721` to be EIP-721 compatible. +# with the built-in interface `IERC721` to be EIP-721 compatible. # If you want to use this interface as a stand-alone interface, -# you must add `implements: ERC721` to this interface and implement +# you must add `implements: IERC721` to this interface and implement # all required events and functions accordingly. -from vyper.interfaces import ERC721 +from ethereum.ercs import IERC721 @external @@ -46,7 +46,7 @@ def supportsInterface(interfaceId: bytes4) -> bool: @return bool The verification whether the contract implements the interface or not. """ - return empty(bool) + return ... @external @@ -56,7 +56,7 @@ def totalSupply() -> uint256: @dev Returns the amount of tokens in existence. @return uint256 The 32-byte token supply. """ - return empty(uint256) + return ... @external @@ -72,7 +72,7 @@ def tokenByIndex(_index: uint256) -> uint256: @return uint256 The 32-byte token ID at index `_index`. """ - return empty(uint256) + return ... @external @@ -89,4 +89,4 @@ def tokenOfOwnerByIndex(_owner: address, _index: uint256) -> uint256: @return uint256 The 32-byte token ID owned by `_owner` at index `_index`. """ - return empty(uint256) + return ... diff --git a/src/snekmate/tokens/interfaces/IERC721Metadata.vy b/src/snekmate/tokens/interfaces/IERC721Metadata.vyi similarity index 84% rename from src/snekmate/tokens/interfaces/IERC721Metadata.vy rename to src/snekmate/tokens/interfaces/IERC721Metadata.vyi index 5fabbf0d..07b29246 100644 --- a/src/snekmate/tokens/interfaces/IERC721Metadata.vy +++ b/src/snekmate/tokens/interfaces/IERC721Metadata.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-721 Optional Metadata Interface Definition @custom:contract-name IERC721Metadata @@ -23,22 +23,22 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 -# @dev We import the `ERC721` interface, which is a built-in +# @dev We import the `IERC721` interface, which is a built-in # interface of the Vyper compiler, to highlight the association # of the custom `IERC721Metadata` interface with the built-in -# `ERC721` interface. +# `IERC721` interface. # @notice The interface `IERC721Metadata` must be used in conjunction -# with the built-in interface `ERC721` to be EIP-721 compatible. +# with the built-in interface `IERC721` to be EIP-721 compatible. # If you want to use this interface as a stand-alone interface, -# you must add `implements: ERC721` to this interface and implement +# you must add `implements: IERC721` to this interface and implement # all required events and functions accordingly. -from vyper.interfaces import ERC721 +from ethereum.ercs import IERC721 @external @@ -54,7 +54,7 @@ def supportsInterface(interfaceId: bytes4) -> bool: @return bool The verification whether the contract implements the interface or not. """ - return empty(bool) + return ... @external @@ -66,7 +66,7 @@ def name() -> String[25]: user-readable string name of the token collection. """ - return empty(String[25]) + return ... @external @@ -78,7 +78,7 @@ def symbol() -> String[5]: user-readable string symbol of the token collection. """ - return empty(String[5]) + return ... @external @@ -92,4 +92,4 @@ def tokenURI(_tokenId: uint256) -> String[512]: @return String The maximum 512-character user-readable string token URI of the `_tokenId` token. """ - return empty(String[512]) + return ... diff --git a/src/snekmate/tokens/interfaces/IERC721Permit.vy b/src/snekmate/tokens/interfaces/IERC721Permit.vyi similarity index 93% rename from src/snekmate/tokens/interfaces/IERC721Permit.vy rename to src/snekmate/tokens/interfaces/IERC721Permit.vyi index cfc1545f..c864fc70 100644 --- a/src/snekmate/tokens/interfaces/IERC721Permit.vy +++ b/src/snekmate/tokens/interfaces/IERC721Permit.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-4494 Interface Definition @custom:contract-name IERC721Permit @@ -28,10 +28,10 @@ """ -# @dev We import and implement the `ERC165` interface, +# @dev We import and implement the `IERC165` interface, # which is a built-in interface of the Vyper compiler. -from vyper.interfaces import ERC165 -implements: ERC165 +from ethereum.ercs import IERC165 +implements: IERC165 @external @@ -47,7 +47,7 @@ def supportsInterface(interfaceId: bytes4) -> bool: @return bool The verification whether the contract implements the interface or not. """ - return empty(bool) + return ... @external @@ -70,7 +70,7 @@ def permit(spender: address, tokenId: uint256, deadline: uint256, v: uint8, r: b @param r The secp256k1 32-byte signature parameter `r`. @param s The secp256k1 32-byte signature parameter `s`. """ - pass + ... @external @@ -81,7 +81,7 @@ def nonces(tokenId: uint256) -> uint256: @param tokenId The 32-byte identifier of the token. @return uint256 The 32-byte `tokenId` nonce. """ - return empty(uint256) + return ... @external @@ -91,4 +91,4 @@ def DOMAIN_SEPARATOR() -> bytes32: @dev Returns the domain separator for the current chain. @return bytes32 The 32-byte domain separator. """ - return empty(bytes32) + return ... diff --git a/src/snekmate/tokens/interfaces/IERC721Receiver.vy b/src/snekmate/tokens/interfaces/IERC721Receiver.vyi similarity index 96% rename from src/snekmate/tokens/interfaces/IERC721Receiver.vy rename to src/snekmate/tokens/interfaces/IERC721Receiver.vyi index ba9db800..1d3e746e 100644 --- a/src/snekmate/tokens/interfaces/IERC721Receiver.vy +++ b/src/snekmate/tokens/interfaces/IERC721Receiver.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-721 Token Receiver Interface Definition @custom:contract-name IERC721Receiver @@ -34,4 +34,4 @@ def onERC721Received(_operator: address, _from: address, _tokenId: uint256, _dat with no specified format. @return bytes4 The 4-byte function selector of `onERC721Received`. """ - return empty(bytes4) + return ... diff --git a/src/snekmate/tokens/mocks/erc1155_mock.vy b/src/snekmate/tokens/mocks/erc1155_mock.vy new file mode 100644 index 00000000..d00e4b61 --- /dev/null +++ b/src/snekmate/tokens/mocks/erc1155_mock.vy @@ -0,0 +1,119 @@ +# pragma version ~=0.4.0rc6 +""" +@title `erc1155` Module Reference Implementation +@custom:contract-name erc1155_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and implement the `IERC165` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC165 +implements: IERC165 + + +# @dev We import and implement the `IERC1155` interface, +# which is written using standard Vyper syntax. +from ..interfaces import IERC1155 +implements: IERC1155 + + +# @dev We import and implement the `IERC1155MetadataURI` +# interface, which is written using standard Vyper +# syntax. +from ..interfaces import IERC1155MetadataURI +implements: IERC1155MetadataURI + + +# @dev We import and initialise the `ownable` module. +from ...auth import ownable as ow +initializes: ow + + +# @dev We import and initialise the `erc1155` module. +from .. import erc1155 +initializes: erc1155[ownable := ow] + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `erc1155` module. The built-in dunder method +# `__interface__` allows you to export all functions of a +# module without specifying the individual functions (see +# https://github.com/vyperlang/vyper/pull/3919). Please take +# note that if you do not know the full interface of a module +# contract, you can get the `.vyi` interface in Vyper by using +# `vyper -f interface your_filename.vy` or the external interface +# by using `vyper -f external_interface your_filename.vy`. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +# Furthermore, if you are not using the full feature set of +# the {erc1155} contract, please ensure you exclude the unused +# ERC-165 interface identifiers in the main contract. One way +# to achieve this would be to not export the `supportsInterface` +# function from {erc1155} in the main contract and implement the +# following function in the main contract instead: +# ```vy +# _SUPPORTED_INTERFACES: constant(bytes4[...]) = [ +# erc1155._SUPPORTED_INTERFACES[0], # The ERC-165 identifier for ERC-165. +# erc1155._SUPPORTED_INTERFACES[1], # The ERC-165 identifier for ERC-1155. +# ... # Any further ERC-165 identifiers you require. +# ] +# +# +# @external +# @view +# def supportsInterface(interface_id: bytes4) -> bool: +# return interface_id in _SUPPORTED_INTERFACES +# ``` +exports: erc1155.__interface__ + + +@deploy +@payable +def __init__(base_uri_: String[80]): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @notice The `owner` role will be assigned to + the `msg.sender`. + @param base_uri_ The maximum 80-character user-readable + string base URI for computing `uri`. + """ + # The following line assigns the `owner` + # to the `msg.sender`. + ow.__init__() + erc1155.__init__(base_uri_) + + +# @dev Custom implementation of the `external` function `safe_mint` +# without access restriction and {IERC1155Receiver-onERC1155Received} +# check to enable the Halmos tests for the no-backdoor and transfer +# properties. +@external +def _customMint(owner: address, id: uint256, amount: uint256): + """ + @dev Creates `amount` tokens of token type `id` and + transfers them to `owner`, increasing the total + supply. + @notice Note that `owner` cannot be the zero address. + @param owner The 20-byte owner address. + @param id The 32-byte identifier of the token. + @param amount The 32-byte token amount to be created. + """ + assert owner != empty(address), "ERC1155Mock: mint to the zero address" + + erc1155._before_token_transfer(empty(address), owner, erc1155._as_singleton_array(id), erc1155._as_singleton_array(amount), b"") + + # In the next line, an overflow is not possible + # due to an arithmetic check of the entire token + # supply in the function `_before_token_transfer`. + erc1155.balanceOf[owner][id] = unsafe_add(erc1155.balanceOf[owner][id], amount) + log IERC1155.TransferSingle(msg.sender, empty(address), owner, id, amount) + + erc1155._after_token_transfer(empty(address), owner, erc1155._as_singleton_array(id), erc1155._as_singleton_array(amount), b"") diff --git a/src/snekmate/tokens/mocks/erc20_mock.vy b/src/snekmate/tokens/mocks/erc20_mock.vy new file mode 100644 index 00000000..e38aa451 --- /dev/null +++ b/src/snekmate/tokens/mocks/erc20_mock.vy @@ -0,0 +1,124 @@ +# pragma version ~=0.4.0rc6 +""" +@title `erc20` Module Reference Implementation +@custom:contract-name erc20_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and implement the `IERC20` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC20 +implements: IERC20 + + +# @dev We import and implement the `IERC20Detailed` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC20Detailed +implements: IERC20Detailed + + +# @dev We import and implement the `IERC20Permit` +# interface, which is written using standard Vyper +# syntax. +from ..interfaces import IERC20Permit +implements: IERC20Permit + + +# @dev We import and implement the `IERC5267` interface, +# which is written using standard Vyper syntax. +from ...utils.interfaces import IERC5267 +implements: IERC5267 + + +# @dev We import and initialise the `ownable` module. +from ...auth import ownable as ow +initializes: ow + + +# @dev We import and initialise the `erc20` module. +from .. import erc20 +initializes: erc20[ownable := ow] + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `erc20` module. The built-in dunder method +# `__interface__` allows you to export all functions of a +# module without specifying the individual functions (see +# https://github.com/vyperlang/vyper/pull/3919). Please take +# note that if you do not know the full interface of a module +# contract, you can get the `.vyi` interface in Vyper by using +# `vyper -f interface your_filename.vy` or the external interface +# by using `vyper -f external_interface your_filename.vy`. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: erc20.__interface__ + + +# @dev The following two parameters are required for the Echidna +# fuzzing test integration: https://github.com/crytic/properties. +isMintableOrBurnable: public(constant(bool)) = True +initialSupply: public(uint256) + + +@deploy +@payable +def __init__(name_: String[25], symbol_: String[5], decimals_: uint8, initial_supply_: uint256, name_eip712_: String[50], version_eip712_: String[20]): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @notice The initial supply of the token as well + as the `owner` role will be assigned to + the `msg.sender`. + @param name_ The maximum 25-character user-readable + string name of the token. + @param symbol_ The maximum 5-character user-readable + string symbol of the token. + @param decimals_ The 1-byte decimal places of the token. + @param initial_supply_ The 32-byte non-decimalised initial + supply of the token. + @param name_eip712_ The maximum 50-character user-readable + string name of the signing domain, i.e. the name + of the dApp or protocol. + @param version_eip712_ The maximum 20-character current + main version of the signing domain. Signatures + from different versions are not compatible. + """ + # The following line assigns the `owner` + # to the `msg.sender`. + ow.__init__() + erc20.__init__(name_, symbol_, decimals_, name_eip712_, version_eip712_) + + # The following line premints an initial token + # supply to the `msg.sender`, which takes the + # underlying `decimals` value into account. + erc20._mint(msg.sender, initial_supply_ * 10 ** convert(decimals_, uint256)) + + # We assign the initial token supply required by + # the Echidna external harness contract. + self.initialSupply = erc20.totalSupply + + +# @dev Duplicate implementation of the `external` function +# `burn_from` to enable the Echidna tests for the external +# burnable properties. +@external +def burnFrom(owner: address, amount: uint256): + """ + @dev Destroys `amount` tokens from `owner`, + deducting from the caller's allowance. + @notice Note that `owner` cannot be the + zero address. Also, the caller must + have an allowance for `owner`'s tokens + of at least `amount`. + @param owner The 20-byte owner address. + @param amount The 32-byte token amount to be destroyed. + """ + erc20._spend_allowance(owner, msg.sender, amount) + erc20._burn(owner, amount) diff --git a/src/snekmate/tokens/mocks/erc721_mock.vy b/src/snekmate/tokens/mocks/erc721_mock.vy new file mode 100644 index 00000000..407b82bb --- /dev/null +++ b/src/snekmate/tokens/mocks/erc721_mock.vy @@ -0,0 +1,152 @@ +# pragma version ~=0.4.0rc6 +""" +@title `erc721` Module Reference Implementation +@custom:contract-name erc721_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and implement the `IERC165` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC165 +implements: IERC165 + + +# @dev We import and implement the `IERC721` interface, +# which is a built-in interface of the Vyper compiler. +from ethereum.ercs import IERC721 +implements: IERC721 + + +# @dev We import and implement the `IERC721Metadata` +# interface, which is written using standard Vyper +# syntax. +from ..interfaces import IERC721Metadata +implements: IERC721Metadata + + +# @dev We import and implement the `IERC721Enumerable` +# interface, which is written using standard Vyper +# syntax. +from ..interfaces import IERC721Enumerable +implements: IERC721Enumerable + + +# @dev We import and implement the `IERC721Permit` +# interface, which is written using standard Vyper +# syntax. +from ..interfaces import IERC721Permit +implements: IERC721Permit + + +# @dev We import and implement the `IERC4906` interface, +# which is written using standard Vyper syntax. +from ..interfaces import IERC4906 +implements: IERC4906 + + +# @dev We import and implement the `IERC5267` interface, +# which is written using standard Vyper syntax. +from ...utils.interfaces import IERC5267 +implements: IERC5267 + + +# @dev We import and initialise the `ownable` module. +from ...auth import ownable as ow +initializes: ow + + +# @dev We import and initialise the `erc721` module. +from .. import erc721 +initializes: erc721[ownable := ow] + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) all `external` functions +# from the `erc721` module. The built-in dunder method +# `__interface__` allows you to export all functions of a +# module without specifying the individual functions (see +# https://github.com/vyperlang/vyper/pull/3919). Please take +# note that if you do not know the full interface of a module +# contract, you can get the `.vyi` interface in Vyper by using +# `vyper -f interface your_filename.vy` or the external interface +# by using `vyper -f external_interface your_filename.vy`. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +# Furthermore, if you are not using the full feature set of +# the {erc721} contract, please ensure you exclude the unused +# ERC-165 interface identifiers in the main contract. One way +# to achieve this would be to not export the `supportsInterface` +# function from {erc721} in the main contract and implement the +# following function in the main contract instead: +# ```vy +# _SUPPORTED_INTERFACES: constant(bytes4[...]) = [ +# erc721._SUPPORTED_INTERFACES[0], # The ERC-165 identifier for ERC-165. +# erc721._SUPPORTED_INTERFACES[1], # The ERC-165 identifier for ERC-721. +# ... # Any further ERC-165 identifiers you require. +# ] +# +# +# @external +# @view +# def supportsInterface(interface_id: bytes4) -> bool: +# return interface_id in _SUPPORTED_INTERFACES +# ``` +exports: erc721.__interface__ + + +# @dev The following two parameters are required for the Echidna +# fuzzing test integration: https://github.com/crytic/properties. +isMintableOrBurnable: public(constant(bool)) = True +usedId: public(HashMap[uint256, bool]) + + +@deploy +@payable +def __init__(name_: String[25], symbol_: String[5], base_uri_: String[80], name_eip712_: String[50], version_eip712_: String[20]): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + @notice The `owner` role will be assigned to + the `msg.sender`. + @param name_ The maximum 25-character user-readable string + name of the token collection. + @param symbol_ The maximum 5-character user-readable string + symbol of the token collection. + @param base_uri_ The maximum 80-character user-readable + string base URI for computing `tokenURI`. + @param name_eip712_ The maximum 50-character user-readable + string name of the signing domain, i.e. the name + of the dApp or protocol. + @param version_eip712_ The maximum 20-character current + main version of the signing domain. Signatures + from different versions are not compatible. + """ + # The following line assigns the `owner` + # to the `msg.sender`. + ow.__init__() + erc721.__init__(name_, symbol_, base_uri_, name_eip712_, version_eip712_) + + +# @dev Custom implementation of the `external` function `safe_mint` +# without access restriction and {IERC721Receiver-onERC721Received} +# check to enable the Echidna tests for the external mintable properties. +@external +def _customMint(owner: address, amount: uint256): + """ + @dev Creates `amount` tokens and assigns them to + `owner`, increasing the total supply. + @notice Note that each `token_id` must not exist + and `owner` cannot be the zero address. + @param owner The 20-byte owner address. + @param amount The 32-byte token amount to be created. + """ + for _: uint256 in range(amount, bound=64): + token_id: uint256 = erc721._counter + erc721._counter = token_id + 1 + erc721._mint(owner, token_id) diff --git a/src/snekmate/utils/ECDSA.vy b/src/snekmate/utils/ECDSA.vy deleted file mode 100644 index 78f1f9d1..00000000 --- a/src/snekmate/utils/ECDSA.vy +++ /dev/null @@ -1,221 +0,0 @@ -# pragma version ^0.3.10 -""" -@title Elliptic Curve Digital Signature Algorithm (ECDSA) Functions -@custom:contract-name ECDSA -@license GNU Affero General Public License v3.0 only -@author pcaversaccio -@notice These functions can be used to verify that a message was signed - by the holder of the private key of a given address. Additionally, - we provide helper functions to handle signed data in Ethereum - contracts based on EIP-191: https://eips.ethereum.org/EIPS/eip-191. - The implementation is inspired by OpenZeppelin's implementation here: - https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol. -@custom:security Signatures must not be used as unique identifiers since the - `ecrecover` EVM precompile allows for malleable (non-unique) - signatures (see EIP-2: https://eips.ethereum.org/EIPS/eip-2) - or signatures can be malleablised using EIP-2098: - https://eips.ethereum.org/EIPS/eip-2098. -""" - - -# @dev Constants used as part of the ECDSA recovery function. -_MALLEABILITY_THRESHOLD: constant(bytes32) = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 -_SIGNATURE_INCREMENT: constant(bytes32) = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - - -@external -@payable -def __init__(): - """ - @dev To omit the opcodes for checking the `msg.value` - in the creation-time EVM bytecode, the constructor - is declared as `payable`. - """ - pass - - -@external -@pure -def recover_sig(hash: bytes32, signature: Bytes[65]) -> address: - """ - @dev Recovers the signer address from a message digest `hash` - and the signature `signature`. - @notice WARNING: This function is vulnerable to a kind of - signature malleability due to accepting EIP-2098 - compact signatures in addition to the traditional - 65-byte signature format. The potentially affected - contracts are those that implement signature reuse - or replay protection by marking the signature itself - as used rather than the signed message or a nonce - included in it. A user may take a signature that has - already been submitted, submit it again in a different - form, and bypass this protection. Also, see OpenZeppelin's - security advisory for more information: - https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h. - @param hash The 32-byte message digest that was signed. - @param signature The secp256k1 64/65-byte signature of `hash`. - @return address The recovered 20-byte signer address. - """ - sig_length: uint256 = len(signature) - # 65-byte case: r,s,v standard signature. - if (sig_length == 65): - r: uint256 = extract32(signature, empty(uint256), output_type=uint256) - s: uint256 = extract32(signature, 32, output_type=uint256) - v: uint256 = convert(slice(signature, 64, 1), uint256) - return self._try_recover_vrs(hash, v, r, s) - # 64-byte case: r,vs signature; see: https://eips.ethereum.org/EIPS/eip-2098. - elif (sig_length == 64): - r: uint256 = extract32(signature, empty(uint256), output_type=uint256) - vs: uint256 = extract32(signature, 32, output_type=uint256) - return self._try_recover_r_vs(hash, r, vs) - else: - return empty(address) - - -@external -@pure -def to_eth_signed_message_hash(hash: bytes32) -> bytes32: - """ - @dev Returns an Ethereum signed message from a 32-byte - message digest `hash`. - @notice This function returns a 32-byte hash that - corresponds to the one signed with the JSON-RPC method: - https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign. - This method is part of EIP-191: - https://eips.ethereum.org/EIPS/eip-191. - @param hash The 32-byte message digest. - @return bytes32 The 32-byte Ethereum signed message. - """ - return keccak256(concat(b"\x19Ethereum Signed Message:\n32", hash)) - - -@external -@pure -def to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32: - """ - @dev Returns an Ethereum signed typed data from a 32-byte - `domain_separator` and a 32-byte `struct_hash`. - @notice This function returns a 32-byte hash that - corresponds to the one signed with the JSON-RPC method: - https://eips.ethereum.org/EIPS/eip-712#specification-of-the-eth_signtypeddata-json-rpc. - This method is part of EIP-712: - https://eips.ethereum.org/EIPS/eip-712. - @param domain_separator The 32-byte domain separator that is - used as part of the EIP-712 encoding scheme. - @param struct_hash The 32-byte struct hash that is used as - part of the EIP-712 encoding scheme. See the definition: - https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. - @return bytes32 The 32-byte Ethereum signed typed data. - """ - return keccak256(concat(b"\x19\x01", domain_separator, struct_hash)) - - -@external -@view -def to_data_with_intended_validator_hash_self(data: Bytes[1_024]) -> bytes32: - """ - @dev Returns an Ethereum signed data with this contract - as the intended validator and a maximum 1,024-byte - payload `data`. - @notice This function structures the data according to - the version `0x00` of EIP-191: - https://eips.ethereum.org/EIPS/eip-191#version-0x00. - @param data The maximum 1,024-byte data to be signed. - @return bytes32 The 32-byte Ethereum signed data. - """ - return self._to_data_with_intended_validator_hash(self, data) - - -@external -@pure -def to_data_with_intended_validator_hash(validator: address, data: Bytes[1_024]) -> bytes32: - """ - @dev Returns an Ethereum signed data with `validator` as - the intended validator and a maximum 1,024-byte payload - `data`. - @notice This function structures the data according to - the version `0x00` of EIP-191: - https://eips.ethereum.org/EIPS/eip-191#version-0x00. - @param validator The 20-byte intended validator address. - @param data The maximum 1,024-byte data to be signed. - @return bytes32 The 32-byte Ethereum signed data. - """ - return self._to_data_with_intended_validator_hash(validator, data) - - -@internal -@pure -def _recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Recovers the signer address from a message digest `hash` - and the secp256k1 signature parameters `v`, `r`, and `s`. - @param hash The 32-byte message digest that was signed. - @param v The secp256k1 1-byte signature parameter `v`. - @param r The secp256k1 32-byte signature parameter `r`. - @param s The secp256k1 32-byte signature parameter `s`. - @return address The recovered 20-byte signer address. - """ - return self._try_recover_vrs(hash, v, r, s) - - -@internal -@pure -def _try_recover_r_vs(hash: bytes32, r: uint256, vs: uint256) -> address: - """ - @dev Recovers the signer address from a message digest `hash` - and the secp256k1 short signature fields `r` and `vs`. - @notice See https://eips.ethereum.org/EIPS/eip-2098 for the - compact signature representation. - @param hash The 32-byte message digest that was signed. - @param r The secp256k1 32-byte signature parameter `r`. - @param vs The secp256k1 32-byte short signature field of `v` and `s`. - @return address The recovered 20-byte signer address. - """ - s: uint256 = vs & convert(_SIGNATURE_INCREMENT, uint256) - # We do not check for an overflow here since the shift operation - # `vs >> 255` results essentially in a `uint8` type (0 or 1) and - # we use `uint256` as result type. - v: uint256 = unsafe_add(vs >> 255, 27) - return self._try_recover_vrs(hash, v, r, s) - - -@internal -@pure -def _try_recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Recovers the signer address from a message digest `hash` - and the secp256k1 signature parameters `v`, `r`, and `s`. - @notice All client implementations of the precompile `ecrecover` - check if the value of `v` is 27 or 28. The references for - the different client implementations can be found here: - https://github.com/ethereum/yellowpaper/pull/860. Thus, - the signature check on the value of `v` is neglected. - @param hash The 32-byte message digest that was signed. - @param v The secp256k1 1-byte signature parameter `v`. - @param r The secp256k1 32-byte signature parameter `r`. - @param s The secp256k1 32-byte signature parameter `s`. - @return address The recovered 20-byte signer address. - """ - assert s <= convert(_MALLEABILITY_THRESHOLD, uint256), "ECDSA: invalid signature `s` value" - - signer: address = ecrecover(hash, v, r, s) - assert signer != empty(address), "ECDSA: invalid signature" - - return signer - - -@internal -@pure -def _to_data_with_intended_validator_hash(validator: address, data: Bytes[1_024]) -> bytes32: - """ - @dev An `internal` helper function that returns an Ethereum - signed data with `validator` as the intended validator - and a maximum 1,024-byte payload `data`. - @notice This function structures the data according to - the version `0x00` of EIP-191: - https://eips.ethereum.org/EIPS/eip-191#version-0x00. - @param validator The 20-byte intended validator address. - @param data The maximum 1,024-byte data to be signed. - @return bytes32 The 32-byte Ethereum signed data. - """ - return keccak256(concat(b"\x19\x00", convert(validator, bytes20), data)) diff --git a/src/snekmate/utils/SignatureChecker.vy b/src/snekmate/utils/SignatureChecker.vy deleted file mode 100644 index 68371c15..00000000 --- a/src/snekmate/utils/SignatureChecker.vy +++ /dev/null @@ -1,191 +0,0 @@ -# pragma version ^0.3.10 -""" -@title ECDSA and EIP-1271 Signature Verification Functions -@custom:contract-name SignatureChecker -@license GNU Affero General Public License v3.0 only -@author pcaversaccio -@notice Signature verification helper functions that can be used - instead of `ECDSA.recover_sig` to seamlessly support both - ECDSA signatures from externally-owned accounts (EOAs) as - well as EIP-1271 (https://eips.ethereum.org/EIPS/eip-1271) - signatures from smart contract wallets like Argent and Gnosis - Safe. For strict EIP-1271 verification, i.e. only valid EIP-1271 - signatures are verified, the function `is_valid_ERC1271_signature_now` - can be called. The implementation is inspired by OpenZeppelin's - implementation here: - https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol. -@custom:security Signatures must not be used as unique identifiers since the - `ecrecover` EVM precompile allows for malleable (non-unique) - signatures (see EIP-2: https://eips.ethereum.org/EIPS/eip-2) - or signatures can be malleablised using EIP-2098: - https://eips.ethereum.org/EIPS/eip-2098. -""" - - -# @dev The 4-byte function selector of `isValidSignature(bytes32,bytes)`. -# @notice If you declare a variable as `public`, -# Vyper automatically generates an `external` -# getter function for the variable. -IERC1271_ISVALIDSIGNATURE_SELECTOR: public(constant(bytes4)) = 0x1626BA7E - - -# @dev Constants used as part of the ECDSA recovery function. -_MALLEABILITY_THRESHOLD: constant(bytes32) = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 -_SIGNATURE_INCREMENT: constant(bytes32) = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - - -@external -@payable -def __init__(): - """ - @dev To omit the opcodes for checking the `msg.value` - in the creation-time EVM bytecode, the constructor - is declared as `payable`. - """ - pass - - -@external -@view -def is_valid_signature_now(signer: address, hash: bytes32, signature: Bytes[65]) -> bool: - """ - @dev Checks if a signature `signature` is valid - for a given `signer` and message digest `hash`. - If the signer is a smart contract, the signature - is validated against that smart contract using - EIP-1271, otherwise it's validated using `ECDSA.recover_sig`. - @notice Unlike ECDSA signatures, contract signatures - are revocable and the result of this function - can therefore change over time. It could return - `True` in block N and `False` in block N+1 (or the opposite). - @param hash The 32-byte message digest that was signed. - @param signature The maximum 65-byte signature of `hash`. - @return bool The verification whether `signature` is valid - for the provided data. - """ - # First check: ECDSA case. - recovered: address = self._recover_sig(hash, signature) - if (recovered == signer): - return True - - # Second check: EIP-1271 case. - return self._is_valid_ERC1271_signature_now(signer, hash, signature) - - -@external -@view -def is_valid_ERC1271_signature_now(signer: address, hash: bytes32, signature: Bytes[65]) -> bool: - """ - @dev Checks if a signature `signature` is valid - for a given `signer` and message digest `hash`. - The signature is validated using EIP-1271. - @notice Unlike ECDSA signatures, contract signatures - are revocable and the result of this function - can therefore change over time. It could return - `True` in block N and `False` in block N+1 (or the opposite). - @param hash The 32-byte message digest that was signed. - @param signature The maximum 65-byte signature of `hash`. - @return bool The verification whether `signature` is valid - for the provided data. - """ - return self._is_valid_ERC1271_signature_now(signer, hash, signature) - - -@internal -@view -def _is_valid_ERC1271_signature_now(signer: address, hash: bytes32, signature: Bytes[65]) -> bool: - """ - @dev This `internal` function is equivalent to - `is_valid_ERC1271_signature_now`, and can be used - for strict EIP-1271 verification. - @notice Unlike ECDSA signatures, contract signatures - are revocable and the result of this function - can therefore change over time. It could return - `True` in block N and `False` in block N+1 (or the opposite). - @param hash The 32-byte message digest that was signed. - @param signature The maximum 65-byte signature of `hash`. - @return bool The verification whether `signature` is valid - for the provided data. - """ - success: bool = empty(bool) - return_data: Bytes[32] = b"" - # The following low-level call does not revert, but instead - # returns `False` if the callable contract does not implement - # the `isValidSignature` function. Since we perform a length - # check of 32 bytes for the return data in the return expression - # at the end, we also return `False` for EOA wallets instead - # of reverting (remember that the EVM always considers a call - # to an EOA as successful with return data `0x`). Furthermore, - # it is important to note that an external call via `raw_call` - # does not perform an external code size check on the target - # address. - success, return_data = \ - raw_call(signer, _abi_encode(hash, signature, method_id=IERC1271_ISVALIDSIGNATURE_SELECTOR), max_outsize=32, is_static_call=True, revert_on_failure=False) - return (success and (len(return_data) == 32) and (convert(return_data, bytes32) == convert(IERC1271_ISVALIDSIGNATURE_SELECTOR, bytes32))) - - -@internal -@pure -def _recover_sig(hash: bytes32, signature: Bytes[65]) -> address: - """ - @dev Sourced from {ECDSA-recover_sig}. - @notice See {ECDSA-recover_sig} for the - function docstring. - """ - sig_length: uint256 = len(signature) - # 65-byte case: r,s,v standard signature. - if (sig_length == 65): - r: uint256 = extract32(signature, empty(uint256), output_type=uint256) - s: uint256 = extract32(signature, 32, output_type=uint256) - v: uint256 = convert(slice(signature, 64, 1), uint256) - return self._try_recover_vrs(hash, v, r, s) - # 64-byte case: r,vs signature; see: https://eips.ethereum.org/EIPS/eip-2098. - elif (sig_length == 64): - r: uint256 = extract32(signature, empty(uint256), output_type=uint256) - vs: uint256 = extract32(signature, 32, output_type=uint256) - return self._try_recover_r_vs(hash, r, vs) - else: - return empty(address) - - -@internal -@pure -def _recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Sourced from {ECDSA-_recover_vrs}. - @notice See {ECDSA-_recover_vrs} for the - function docstring. - """ - return self._try_recover_vrs(hash, v, r, s) - - -@internal -@pure -def _try_recover_r_vs(hash: bytes32, r: uint256, vs: uint256) -> address: - """ - @dev Sourced from {ECDSA-_try_recover_r_vs}. - @notice See {ECDSA-_try_recover_r_vs} for the - function docstring. - """ - s: uint256 = vs & convert(_SIGNATURE_INCREMENT, uint256) - # We do not check for an overflow here since the shift operation - # `vs >> 255` results essentially in a `uint8` type (0 or 1) and - # we use `uint256` as result type. - v: uint256 = unsafe_add(vs >> 255, 27) - return self._try_recover_vrs(hash, v, r, s) - - -@internal -@pure -def _try_recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: - """ - @dev Sourced from {ECDSA-_try_recover_vrs}. - @notice See {ECDSA-_try_recover_vrs} for the - function docstring. - """ - assert s <= convert(_MALLEABILITY_THRESHOLD, uint256), "ECDSA: invalid signature `s` value" - - signer: address = ecrecover(hash, v, r, s) - assert signer != empty(address), "ECDSA: invalid signature" - - return signer diff --git a/src/snekmate/utils/Base64.vy b/src/snekmate/utils/base64.vy similarity index 95% rename from src/snekmate/utils/Base64.vy rename to src/snekmate/utils/base64.vy index 813a1ab7..b2a8ee5c 100644 --- a/src/snekmate/utils/Base64.vy +++ b/src/snekmate/utils/base64.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Base64 Encoding and Decoding Functions -@custom:contract-name Base64 +@custom:contract-name base64 @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions can be used to encode bytes or to decode strings @@ -29,7 +29,7 @@ _TABLE_STD_CHARS: constant(String[65]) = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl _TABLE_URL_CHARS: constant(String[65]) = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=" -@external +@deploy @payable def __init__(): """ @@ -40,9 +40,9 @@ def __init__(): pass -@external +@internal @pure -def encode(data: Bytes[_DATA_INPUT_BOUND], base64_url: bool) -> DynArray[String[4], _DATA_OUTPUT_BOUND]: +def _encode(data: Bytes[_DATA_INPUT_BOUND], base64_url: bool) -> DynArray[String[4], _DATA_OUTPUT_BOUND]: """ @dev Encodes a `Bytes` array using the Base64 binary-to-text encoding scheme. @@ -81,7 +81,7 @@ def encode(data: Bytes[_DATA_INPUT_BOUND], base64_url: bool) -> DynArray[String[ char_chunks: DynArray[String[4], _DATA_OUTPUT_BOUND] = [] idx: uint256 = empty(uint256) - for _ in range(_DATA_INPUT_BOUND): + for _: uint256 in range(_DATA_INPUT_BOUND): # For the Base64 encoding, three bytes (= chunk) # of the bytestream (= 24 bits) are divided into # four 6-bit blocks. @@ -144,9 +144,9 @@ def encode(data: Bytes[_DATA_INPUT_BOUND], base64_url: bool) -> DynArray[String[ return char_chunks -@external +@internal @pure -def decode(data: String[_DATA_OUTPUT_BOUND], base64_url: bool) -> DynArray[Bytes[3], _DATA_INPUT_BOUND]: +def _decode(data: String[_DATA_OUTPUT_BOUND], base64_url: bool) -> DynArray[Bytes[3], _DATA_INPUT_BOUND]: """ @dev Decodes a `String` input using the Base64 binary-to-text encoding scheme. @@ -172,11 +172,11 @@ def decode(data: String[_DATA_OUTPUT_BOUND], base64_url: bool) -> DynArray[Bytes # If the length of the encoded input is not a # multiple of four, it is an invalid input. - assert data_length % 4 == empty(uint256), "Base64: length mismatch" + assert data_length % 4 == empty(uint256), "base64: length mismatch" result: DynArray[Bytes[3], _DATA_INPUT_BOUND] = [] idx: uint256 = empty(uint256) - for _ in range(_DATA_OUTPUT_BOUND): + for _: uint256 in range(_DATA_OUTPUT_BOUND): # Each of these four characters represents # a 6-bit index in the Base64 character list # which, when concatenated, gives the 24-bit @@ -279,7 +279,7 @@ def _index_of(char: String[1], base64_url: bool) -> uint256: `char` in the Base64 encoding table. """ pos: uint256 = empty(uint256) - for _ in range(len(_TABLE_URL_CHARS)): + for _: uint256 in range(len(_TABLE_URL_CHARS)): # Base64 encoding with an URL and filename-safe # alphabet. if (base64_url): @@ -298,6 +298,6 @@ def _index_of(char: String[1], base64_url: bool) -> uint256: # If no matching character is found, it is an # invalid input. - assert pos < len(_TABLE_URL_CHARS), "Base64: invalid string" + assert pos < len(_TABLE_URL_CHARS), "base64: invalid string" return pos diff --git a/src/snekmate/utils/BatchDistributor.vy b/src/snekmate/utils/batch_distributor.vy similarity index 73% rename from src/snekmate/utils/BatchDistributor.vy rename to src/snekmate/utils/batch_distributor.vy index 4836c121..65fab8e0 100644 --- a/src/snekmate/utils/BatchDistributor.vy +++ b/src/snekmate/utils/batch_distributor.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Batch Sending Both Native and ERC-20 Tokens -@custom:contract-name BatchDistributor +@custom:contract-name batch_distributor @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions can be used for batch sending @@ -13,9 +13,9 @@ """ -# @dev We import the `ERC20` interface, which is a +# @dev We import the `IERC20` interface, which is a # built-in interface of the Vyper compiler. -from vyper.interfaces import ERC20 +from ethereum.ercs import IERC20 # @dev Transaction struct for the transaction payload. @@ -29,7 +29,7 @@ struct Batch: txns: DynArray[Transaction, max_value(uint8)] -@external +@deploy @payable def __init__(): """ @@ -40,16 +40,18 @@ def __init__(): pass -@external -@payable -@nonreentrant("lock") -def distribute_ether(data: Batch): +@internal +@nonreentrant +def _distribute_ether(data: Batch): """ @dev Distributes ether, denominated in wei, to a predefined batch of recipient addresses. @notice In the event that excessive ether is sent, the residual amount is returned back to the - `msg.sender`. + `msg.sender`. Please note that you must add the + `payable` decorator to any `external` function + that calls the `internal` function `_distribute_ether` + to enable the handling of ether. Furthermore, it is important to note that an external call via `raw_call` does not perform @@ -58,7 +60,7 @@ def distribute_ether(data: Batch): of tuples that contain each a recipient address & ether amount in wei. """ - for txn in data.txns: + for txn: Transaction in data.txns: # A low-level call is used to guarantee compatibility # with smart contract wallets. As a general pre-emptive # safety measure, a reentrancy guard is used. @@ -71,14 +73,15 @@ def distribute_ether(data: Batch): raw_call(msg.sender, b"", value=self.balance) -@external -def distribute_token(token: ERC20, data: Batch): +@internal +@nonreentrant +def _distribute_token(token: IERC20, data: Batch): """ @dev Distributes ERC-20 tokens, denominated in their corresponding lowest unit, to a predefined batch of recipient addresses. @notice To deal with (potentially) non-compliant ERC-20 tokens that do have no return value, we use the kwarg `default_return_value` for external - calls. This function was introduced in Vyper version 0.3.4. For more + calls. This function was introduced in Vyper version `0.3.4`. For more details see: - https://github.com/vyperlang/vyper/pull/2839, - https://github.com/vyperlang/vyper/issues/2812, @@ -86,20 +89,24 @@ def distribute_token(token: ERC20, data: Batch): Note: Since we cast the token address into the official ERC-20 interface, the use of non-compliant ERC-20 tokens is prevented by design. Nevertheless, we keep this guardrail for security reasons. - @param token ERC-20 token contract address. + @param token The ERC-20 compatible (i.e. ERC-777 is also + viable) token contract address. @param data Nested struct object that contains an array of tuples that contain each a recipient address & token amount. + @custom:security To prevent a potential cross-function reentrancy via + `_distribute_ether`, as pre-emptive safety measure, + a reentrancy guard is used. """ total: uint256 = empty(uint256) - for txn in data.txns: + for txn: Transaction in data.txns: total += txn.amount # It is important to note that an external call via interface casting # always performs an external code size check on the target address unless # you add the kwarg `skip_contract_check=True`. If the check fails (i.e. # the target address is an EOA), the call reverts. - assert token.transferFrom(msg.sender, self, total, default_return_value=True), "BatchDistributor: transferFrom operation did not succeed" + assert extcall token.transferFrom(msg.sender, self, total, default_return_value=True), "batch_distributor: transferFrom operation did not succeed" - for txn in data.txns: - assert token.transfer(txn.recipient, txn.amount, default_return_value=True), "BatchDistributor: transfer operation did not succeed" + for txn: Transaction in data.txns: + assert extcall token.transfer(txn.recipient, txn.amount, default_return_value=True), "batch_distributor: transfer operation did not succeed" diff --git a/src/snekmate/utils/Create2Address.vy b/src/snekmate/utils/create2_address.vy similarity index 74% rename from src/snekmate/utils/Create2Address.vy rename to src/snekmate/utils/create2_address.vy index 4effe643..15c126db 100644 --- a/src/snekmate/utils/Create2Address.vy +++ b/src/snekmate/utils/create2_address.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title `CREATE2` EVM Opcode Utility Functions for Address Calculations -@custom:contract-name Create2Address +@custom:contract-name create2_address @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions can be used to compute in advance the address @@ -18,7 +18,7 @@ _COLLISION_OFFSET: constant(bytes1) = 0xFF -@external +@deploy @payable def __init__(): """ @@ -29,9 +29,9 @@ def __init__(): pass -@external +@internal @view -def compute_address_self(salt: bytes32, bytecode_hash: bytes32) -> address: +def _compute_address_self(salt: bytes32, bytecode_hash: bytes32) -> address: """ @dev Returns the address where a contract will be stored if deployed via this contract using the `CREATE2` opcode. @@ -46,9 +46,9 @@ def compute_address_self(salt: bytes32, bytecode_hash: bytes32) -> address: return self._compute_address(salt, bytecode_hash, self) -@external +@internal @pure -def compute_address(salt: bytes32, bytecode_hash: bytes32, deployer: address) -> address: +def _compute_address(salt: bytes32, bytecode_hash: bytes32, deployer: address) -> address: """ @dev Returns the address where a contract will be stored if deployed via `deployer` using the `CREATE2` opcode. @@ -61,24 +61,6 @@ def compute_address(salt: bytes32, bytecode_hash: bytes32, deployer: address) -> @param deployer The 20-byte deployer address. @return address The 20-byte address where a contract will be stored. """ - return self._compute_address(salt, bytecode_hash, deployer) - - -@internal -@pure -def _compute_address(salt: bytes32, bytecode_hash: bytes32, deployer: address) -> address: - """ - @dev An `internal` helper function that returns the address - where a contract will be stored if deployed via `deployer` - using the `CREATE2` opcode. Any change in the `bytecode_hash` - or `salt` values will result in a new destination address. - @param salt The 32-byte random value used to create the contract - address. - @param bytecode_hash The 32-byte bytecode digest of the contract - creation bytecode. - @param deployer The 20-byte deployer address. - @return address The 20-byte address where a contract will be stored. - """ data: bytes32 = keccak256(concat(_COLLISION_OFFSET, convert(deployer, bytes20), salt, bytecode_hash)) return self._convert_keccak256_2_address(data) diff --git a/src/snekmate/utils/CreateAddress.vy b/src/snekmate/utils/create_address.vy similarity index 75% rename from src/snekmate/utils/CreateAddress.vy rename to src/snekmate/utils/create_address.vy index 648df8a7..fbf5f1da 100644 --- a/src/snekmate/utils/CreateAddress.vy +++ b/src/snekmate/utils/create_address.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title `CREATE` EVM Opcode Utility Functions for Address Calculations -@custom:contract-name CreateAddress +@custom:contract-name create_address @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions can be used to compute in advance the address @@ -12,7 +12,7 @@ """ -@external +@deploy @payable def __init__(): """ @@ -23,51 +23,27 @@ def __init__(): pass -@external +@internal @view -def compute_address_rlp_self(nonce: uint256) -> address: +def _compute_address_rlp_self(nonce: uint256) -> address: """ @dev Returns the address where a contract will be stored if deployed via this contract using the `CREATE` opcode. - @param nonce The next 32-byte nonce of this contract. + @param nonce The 32-byte account nonce of this contract. @return address The 20-byte address where a contract will be stored. """ return self._compute_address_rlp(self, nonce) -@external +@internal @pure -def compute_address_rlp(deployer: address, nonce: uint256) -> address: +def _compute_address_rlp(deployer: address, nonce: uint256) -> address: """ @dev Returns the address where a contract will be stored if deployed via `deployer` using the `CREATE` opcode. For the specification of the Recursive Length Prefix (RLP) encoding scheme, please refer to p. 19 of the Ethereum Yellow Paper (https://ethereum.github.io/yellowpaper/paper.pdf) - and the Ethereum Wiki (https://eth.wiki/fundamentals/rlp). - For further insights also, see the following issue: - https://github.com/transmissions11/solmate/issues/207. - - Based on the EIP-161 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md) - specification, all contract accounts on the Ethereum mainnet - are initiated with `nonce = 1`. Thus, the first contract address - created by another contract is calculated with a non-zero nonce. - @param deployer The 20-byte deployer address. - @param nonce The next 32-byte nonce of the deployer address. - @return address The 20-byte address where a contract will be stored. - """ - return self._compute_address_rlp(deployer, nonce) - - -@internal -@pure -def _compute_address_rlp(deployer: address, nonce: uint256) -> address: - """ - @dev An `internal` helper function that returns the address where a - contract will be stored if deployed via `deployer` using the - `CREATE` opcode. For the specification of the Recursive Length - Prefix (RLP) encoding scheme, please refer to p. 19 of the Ethereum - Yellow Paper (https://ethereum.github.io/yellowpaper/paper.pdf) and the Ethereum Wiki (https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp). For further insights also, see the following issue: https://github.com/transmissions11/solmate/issues/207. @@ -77,14 +53,14 @@ def _compute_address_rlp(deployer: address, nonce: uint256) -> address: are initiated with `nonce = 1`. Thus, the first contract address created by another contract is calculated with a non-zero nonce. @param deployer The 20-byte deployer address. - @param nonce The next 32-byte nonce of the deployer address. + @param nonce The 32-byte account nonce of the deployer address. @return address The 20-byte address where a contract will be stored. """ length: bytes1 = 0x94 # The theoretical allowed limit, based on EIP-2681, for an # account nonce is 2**64-2: https://eips.ethereum.org/EIPS/eip-2681. - assert nonce < convert(max_value(uint64), uint256), "RLP: invalid nonce value" + assert nonce < convert(max_value(uint64), uint256), "create_address: invalid nonce value" # The integer zero is treated as an empty byte string and # therefore has only one length prefix, 0x80, which is @@ -117,8 +93,8 @@ def _compute_address_rlp(deployer: address, nonce: uint256) -> address: return self._convert_keccak256_2_address(keccak256(concat(0xdc, length, convert(deployer, bytes20), 0x86, convert(convert(nonce, uint48), bytes6)))) elif (nonce <= convert(max_value(uint56), uint256)): return self._convert_keccak256_2_address(keccak256(concat(0xdd, length, convert(deployer, bytes20), 0x87, convert(convert(nonce, uint56), bytes7)))) - else: - return self._convert_keccak256_2_address(keccak256(concat(0xde, length, convert(deployer, bytes20), 0x88, convert(convert(nonce, uint64), bytes8)))) + + return self._convert_keccak256_2_address(keccak256(concat(0xde, length, convert(deployer, bytes20), 0x88, convert(convert(nonce, uint64), bytes8)))) @internal diff --git a/src/snekmate/utils/ecdsa.vy b/src/snekmate/utils/ecdsa.vy new file mode 100644 index 00000000..ef493126 --- /dev/null +++ b/src/snekmate/utils/ecdsa.vy @@ -0,0 +1,135 @@ +# pragma version ~=0.4.0rc6 +""" +@title Elliptic Curve Digital Signature Algorithm (ECDSA) Secp256k1-Based Functions +@custom:contract-name ecdsa +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +@notice These functions can be used to verify that a message was signed by + the holder of the private key of a given address. All cryptographic + calculations are based on the Ethereum-native secp256k1 elliptic curve + (see https://en.bitcoin.it/wiki/Secp256k1). For verification functions + based on the NIST P-256 elliptic curve (also known as secp256r1), see + the {p256} contract. The implementation is inspired by OpenZeppelin's + implementation here: + https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol. +@custom:security Signatures must not be used as unique identifiers since the + `ecrecover` EVM precompile allows for malleable (non-unique) + signatures (see EIP-2: https://eips.ethereum.org/EIPS/eip-2) + or signatures can be malleablised using EIP-2098: + https://eips.ethereum.org/EIPS/eip-2098. +""" + + +# @dev Constants used as part of the ECDSA recovery function. +_MALLEABILITY_THRESHOLD: constant(uint256) = 57_896_044_618_658_097_711_785_492_504_343_953_926_418_782_139_537_452_191_302_581_570_759_080_747_168 +_SIGNATURE_INCREMENT: constant(uint256) = 57_896_044_618_658_097_711_785_492_504_343_953_926_634_992_332_820_282_019_728_792_003_956_564_819_967 + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@internal +@pure +def _recover_sig(hash: bytes32, signature: Bytes[65]) -> address: + """ + @dev Recovers the signer address from a message digest `hash` + and the signature `signature`. + @notice WARNING: This function is vulnerable to a kind of + signature malleability due to accepting EIP-2098 + compact signatures in addition to the traditional + 65-byte signature format. The potentially affected + contracts are those that implement signature reuse + or replay protection by marking the signature itself + as used rather than the signed message or a nonce + included in it. A user may take a signature that has + already been submitted, submit it again in a different + form, and bypass this protection. Also, see OpenZeppelin's + security advisory for more information: + https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h. + @param hash The 32-byte message digest that was signed. + @param signature The secp256k1 64/65-byte signature of `hash`. + @return address The recovered 20-byte signer address. + """ + sig_length: uint256 = len(signature) + # 65-byte case: `(r,s,v)` standard signature. + if (sig_length == 65): + r: uint256 = extract32(signature, empty(uint256), output_type=uint256) + s: uint256 = extract32(signature, 32, output_type=uint256) + v: uint256 = convert(slice(signature, 64, 1), uint256) + return self._try_recover_vrs(hash, v, r, s) + # 64-byte case: `(r,vs)` signature; see: https://eips.ethereum.org/EIPS/eip-2098. + elif (sig_length == 64): + r: uint256 = extract32(signature, empty(uint256), output_type=uint256) + vs: uint256 = extract32(signature, 32, output_type=uint256) + return self._try_recover_r_vs(hash, r, vs) + + return empty(address) + + +@internal +@pure +def _recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: + """ + @dev Recovers the signer address from a message digest `hash` + and the secp256k1 signature parameters `v`, `r`, and `s`. + @param hash The 32-byte message digest that was signed. + @param v The secp256k1 1-byte signature parameter `v`. + @param r The secp256k1 32-byte signature parameter `r`. + @param s The secp256k1 32-byte signature parameter `s`. + @return address The recovered 20-byte signer address. + """ + return self._try_recover_vrs(hash, v, r, s) + + +@internal +@pure +def _try_recover_r_vs(hash: bytes32, r: uint256, vs: uint256) -> address: + """ + @dev Recovers the signer address from a message digest `hash` + and the secp256k1 short signature fields `r` and `vs`. + @notice See https://eips.ethereum.org/EIPS/eip-2098 for the + compact signature representation. + @param hash The 32-byte message digest that was signed. + @param r The secp256k1 32-byte signature parameter `r`. + @param vs The secp256k1 32-byte short signature field of `v` and `s`. + @return address The recovered 20-byte signer address. + """ + s: uint256 = vs & _SIGNATURE_INCREMENT + # We do not check for an overflow here since the shift operation + # `vs >> 255` results essentially in a `uint8` type (`0` or `1`) and + # we use `uint256` as result type. + v: uint256 = unsafe_add(vs >> 255, 27) + return self._try_recover_vrs(hash, v, r, s) + + +@internal +@pure +def _try_recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address: + """ + @dev Recovers the signer address from a message digest `hash` + and the secp256k1 signature parameters `v`, `r`, and `s`. + @notice All client implementations of the precompile `ecrecover` + check if the value of `v` is `27` or `28`. The references + for the different client implementations can be found here: + https://github.com/ethereum/yellowpaper/pull/860. Thus, + the signature check on the value of `v` is neglected. + @param hash The 32-byte message digest that was signed. + @param v The secp256k1 1-byte signature parameter `v`. + @param r The secp256k1 32-byte signature parameter `r`. + @param s The secp256k1 32-byte signature parameter `s`. + @return address The recovered 20-byte signer address. + """ + assert s <= _MALLEABILITY_THRESHOLD, "ecdsa: invalid signature `s` value" + + signer: address = ecrecover(hash, v, r, s) + assert signer != empty(address), "ecdsa: invalid signature" + + return signer diff --git a/src/snekmate/utils/EIP712DomainSeparator.vy b/src/snekmate/utils/eip712_domain_separator.vy similarity index 82% rename from src/snekmate/utils/EIP712DomainSeparator.vy rename to src/snekmate/utils/eip712_domain_separator.vy index 96821314..3759207e 100644 --- a/src/snekmate/utils/EIP712DomainSeparator.vy +++ b/src/snekmate/utils/eip712_domain_separator.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-712 Domain Separator -@custom:contract-name EIP712DomainSeparator +@custom:contract-name eip712_domain_separator @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice These functions are part of EIP-712: https://eips.ethereum.org/EIPS/eip-712. @@ -21,6 +21,13 @@ import interfaces.IERC5267 as IERC5267 implements: IERC5267 +# @dev We import the `message_hash_utils` module. +# @notice Please note that the `message_hash_utils` +# module is stateless and therefore does not require +# the `uses` keyword for usage. +from . import message_hash_utils + + # @dev The 32-byte type hash for the EIP-712 domain separator. _TYPE_HASH: constant(bytes32) = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") @@ -47,13 +54,7 @@ _VERSION: immutable(String[20]) _HASHED_VERSION: immutable(bytes32) -# @dev May be emitted to signal that the domain could -# have changed. -event EIP712DomainChanged: - pass - - -@external +@deploy @payable def __init__(name_: String[50], version_: String[20]): """ @@ -83,32 +84,7 @@ def __init__(name_: String[50], version_: String[20]): @external @view -def domain_separator_v4() -> bytes32: - """ - @dev Returns the domain separator for the current chain. - @return bytes32 The 32-byte domain separator. - """ - return self._domain_separator_v4() - - -@external -@view -def hash_typed_data_v4(struct_hash: bytes32) -> bytes32: - """ - @dev Returns the hash of the fully encoded EIP-712 - message for this domain. - @notice The definition of the hashed struct can be found here: - https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. - @param struct_hash The 32-byte hashed struct. - @return bytes32 The 32-byte fully encoded EIP712 - message hash for this domain. - """ - return self._to_typed_data_hash(self._domain_separator_v4(), struct_hash) - - -@external -@view -def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 128]): +def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 32]): """ @dev Returns the fields and values that describe the domain separator used by this contract for EIP-712 signatures. @@ -129,21 +105,20 @@ def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32 @return DynArray The 32-byte array of EIP-712 extensions. """ # Note that `\x0f` equals `01111`. - return (convert(b"\x0f", bytes1), _NAME, _VERSION, chain.id, self, empty(bytes32), empty(DynArray[uint256, 128])) + return (convert(b"\x0f", bytes1), _NAME, _VERSION, chain.id, self, empty(bytes32), empty(DynArray[uint256, 32])) @internal @view def _domain_separator_v4() -> bytes32: """ - @dev An `internal` helper function that returns the domain separator - for the current chain. + @dev Returns the domain separator for the current chain. @return bytes32 The 32-byte domain separator. """ - if (self == _CACHED_SELF and chain.id == _CACHED_CHAIN_ID): + if ((self == _CACHED_SELF) and (chain.id == _CACHED_CHAIN_ID)): return _CACHED_DOMAIN_SEPARATOR - else: - return self._build_domain_separator() + + return self._build_domain_separator() @internal @@ -157,11 +132,15 @@ def _build_domain_separator() -> bytes32: @internal -@pure -def _to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32: +@view +def _hash_typed_data_v4(struct_hash: bytes32) -> bytes32: """ - @dev Sourced from {ECDSA-to_typed_data_hash}. - @notice See {ECDSA-to_typed_data_hash} for the - function docstring. + @dev Returns the hash of the fully encoded EIP-712 + message for this domain. + @notice The definition of the hashed struct can be found here: + https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. + @param struct_hash The 32-byte hashed struct. + @return bytes32 The 32-byte fully encoded EIP712 + message hash for this domain. """ - return keccak256(concat(b"\x19\x01", domain_separator, struct_hash)) + return message_hash_utils._to_typed_data_hash(self._domain_separator_v4(), struct_hash) diff --git a/src/snekmate/utils/interfaces/IERC1271.vyi b/src/snekmate/utils/interfaces/IERC1271.vyi new file mode 100644 index 00000000..d4f68cf6 --- /dev/null +++ b/src/snekmate/utils/interfaces/IERC1271.vyi @@ -0,0 +1,29 @@ +# pragma version ~=0.4.0rc6 +""" +@title EIP-1271 Interface Definition +@custom:contract-name IERC1271 +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +@notice The ERC-1271 standard defines a method by which any + contract can verify whether a signature on behalf of + a particular contract is valid. The ERC-165 identifier + for this interface is `0x1626BA7E`. For more details, + please refer to: + https://eips.ethereum.org/EIPS/eip-1271#specification. + + On how to use interfaces in Vyper, please visit: + https://vyper.readthedocs.io/en/latest/interfaces.html#interfaces. +""" + + +@external +@view +def isValidSignature(_hash: bytes32, _signature: Bytes[65]) -> bytes4: + """ + @dev Returns the 4-byte magic value `0x1626BA7E` if the + verification passes. + @param _hash The 32-byte message digest that was signed. + @param _signature The secp256k1 64/65-byte signature of `_hash`. + @return bytes4 The 4-byte magic value. + """ + return ... diff --git a/src/snekmate/utils/interfaces/IERC5267.vy b/src/snekmate/utils/interfaces/IERC5267.vyi similarity index 91% rename from src/snekmate/utils/interfaces/IERC5267.vy rename to src/snekmate/utils/interfaces/IERC5267.vyi index 80d9fc5c..2b68cef6 100644 --- a/src/snekmate/utils/interfaces/IERC5267.vy +++ b/src/snekmate/utils/interfaces/IERC5267.vyi @@ -1,4 +1,4 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title EIP-5267 Interface Definition @custom:contract-name IERC5267 @@ -33,7 +33,7 @@ event EIP712DomainChanged: @external @view -def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 128]): +def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 32]): """ @dev Returns the fields and values that describe the domain separator used by this contract for EIP-712 signatures. @@ -53,4 +53,4 @@ def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32 @return bytes32 The 32-byte disambiguation salt for the protocol. @return DynArray The 32-byte array of EIP-712 extensions. """ - return (empty(bytes1), empty(String[50]), empty(String[20]), empty(uint256), empty(address), empty(bytes32), empty(DynArray[uint256, 128])) + return ... diff --git a/src/snekmate/utils/Math.vy b/src/snekmate/utils/math.vy similarity index 87% rename from src/snekmate/utils/Math.vy rename to src/snekmate/utils/math.vy index 6a75faaa..5757cba4 100644 --- a/src/snekmate/utils/Math.vy +++ b/src/snekmate/utils/math.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Standard Mathematical Utility Functions -@custom:contract-name Math +@custom:contract-name math @license GNU Affero General Public License v3.0 only @author pcaversaccio @custom:coauthor bout3fiddy @@ -10,24 +10,22 @@ function is inspired by an existing implementation, it is properly referenced in the function docstring. The following functions have been added for convenience: - - `uint256_average` (`external` `pure` function), - - `int256_average` (`external` `pure` function), - - `ceil_div` (`external` `pure` function), - - `signum` (`external` `pure` function), - - `mul_div` (`external` `pure` function), - - `log_2` (`external` `pure` function), - - `log_10` (`external` `pure` function), - - `log_256` (`external` `pure` function), - - `wad_ln` (`external` `pure` function), - - `wad_exp` (`external` `pure` function), - - `cbrt` (`external` `pure` function), - - `wad_cbrt` (`external` `pure` function), - - `_log_2` (`internal` `pure` function), + - `_uint256_average` (`internal` `pure` function), + - `_int256_average` (`internal` `pure` function), + - `_ceil_div` (`internal` `pure` function), + - `_signum` (`internal` `pure` function), + - `_mul_div` (`internal` `pure` function), + - `_log2` (`internal` `pure` function), + - `_log10` (`internal` `pure` function), + - `_log256` (`internal` `pure` function), + - `_wad_ln` (`internal` `pure` function), + - `_wad_exp` (`internal` `pure` function), + - `_cbrt` (`internal` `pure` function), - `_wad_cbrt` (`internal` `pure` function). """ -@external +@deploy @payable def __init__(): """ @@ -38,9 +36,9 @@ def __init__(): pass -@external +@internal @pure -def uint256_average(x: uint256, y: uint256) -> uint256: +def _uint256_average(x: uint256, y: uint256) -> uint256: """ @dev Returns the average of two 32-byte unsigned integers. @notice Note that the result is rounded towards zero. For @@ -55,9 +53,9 @@ def uint256_average(x: uint256, y: uint256) -> uint256: return unsafe_add(x & y, (x ^ y) >> 1) -@external +@internal @pure -def int256_average(x: int256, y: int256) -> int256: +def _int256_average(x: int256, y: int256) -> int256: """ @dev Returns the average of two 32-byte signed integers. @notice Note that the result is rounded towards infinity. @@ -72,9 +70,9 @@ def int256_average(x: int256, y: int256) -> int256: return unsafe_add(unsafe_add(x >> 1, y >> 1), x & y & 1) -@external +@internal @pure -def ceil_div(x: uint256, y: uint256) -> uint256: +def _ceil_div(x: uint256, y: uint256) -> uint256: """ @dev Calculates "ceil(x / y)" for any strictly positive `y`. @notice The implementation is inspired by OpenZeppelin's @@ -84,15 +82,15 @@ def ceil_div(x: uint256, y: uint256) -> uint256: @param y The 32-byte denominator. @return uint256 The 32-byte rounded up result of "x/y". """ - assert y != empty(uint256), "Math: ceil_div division by zero" + assert y != empty(uint256), "math: ceil_div division by zero" # Due to a known compiler bug (https://github.com/vyperlang/vyper/issues/3480), # we use `0` instead of `empty(uint256)` as return value. return 0 if (x == empty(uint256)) else unsafe_add(unsafe_div(x - 1, y), 1) -@external +@internal @pure -def signum(x: int256) -> int256: +def _signum(x: int256) -> int256: """ @dev Returns the indication of the sign of a 32-byte signed integer. @notice The function returns `-1` if `x < 0`, `0` if `x == 0`, and `1` @@ -105,9 +103,9 @@ def signum(x: int256) -> int256: return unsafe_sub(convert((x > 0), int256), convert((x < 0), int256)) -@external +@internal @pure -def mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint256: +def _mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint256: """ @dev Calculates "(x * y) / denominator" in 512-bit precision, following the selected rounding direction. @@ -125,7 +123,7 @@ def mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint @return uint256 The 32-byte calculation result. """ # Handle division by zero. - assert denominator != empty(uint256), "Math: mul_div division by zero" + assert denominator != empty(uint256), "math: mul_div division by zero" # 512-bit multiplication "[prod1 prod0] = x * y". # Compute the product "mod 2**256" and "mod 2**256 - 1". @@ -145,18 +143,18 @@ def mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint # Handling of non-overflow cases, 256 by 256 division. if (prod1 == empty(uint256)): - if (roundup and uint256_mulmod(x, y, denominator) != empty(uint256)): + if ((roundup) and (uint256_mulmod(x, y, denominator) != empty(uint256))): # Calculate "ceil((x * y) / denominator)". The following # line cannot overflow because we have the previous check # "(x * y) % denominator != 0", which accordingly rules out # the possibility of "x * y = 2**256 - 1" and `denominator == 1`. return unsafe_add(unsafe_div(prod0, denominator), 1) - else: - return unsafe_div(prod0, denominator) + + return unsafe_div(prod0, denominator) # Ensure that the result is less than 2**256. Also, # prevents that `denominator == 0`. - assert denominator > prod1, "Math: mul_div overflow" + assert denominator > prod1, "math: mul_div overflow" ####################### # 512 by 256 Division # @@ -215,7 +213,7 @@ def mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint # `prod1` is no longer necessary. result: uint256 = unsafe_mul(prod0, inverse) - if (roundup and uint256_mulmod(x, y, denominator) != empty(uint256)): + if ((roundup) and (uint256_mulmod(x, y, denominator) != empty(uint256))): # Calculate "ceil((x * y) / denominator)". The following # line uses intentionally checked arithmetic to prevent # a theoretically possible overflow. @@ -224,9 +222,9 @@ def mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint return result -@external +@internal @pure -def log_2(x: uint256, roundup: bool) -> uint256: +def _log2(x: uint256, roundup: bool) -> uint256: """ @dev Returns the log in base 2 of `x`, following the selected rounding direction. @@ -243,12 +241,44 @@ def log_2(x: uint256, roundup: bool) -> uint256: if (x == empty(uint256)): return empty(uint256) - return self._log_2(x, roundup) + value: uint256 = x + result: uint256 = empty(uint256) + + # The following lines cannot overflow because we have the well-known + # decay behaviour of `log2(max_value(uint256)) < max_value(uint256)`. + if (x >> 128 != empty(uint256)): + value = x >> 128 + result = 128 + if (value >> 64 != empty(uint256)): + value = value >> 64 + result = unsafe_add(result, 64) + if (value >> 32 != empty(uint256)): + value = value >> 32 + result = unsafe_add(result, 32) + if (value >> 16 != empty(uint256)): + value = value >> 16 + result = unsafe_add(result, 16) + if (value >> 8 != empty(uint256)): + value = value >> 8 + result = unsafe_add(result, 8) + if (value >> 4 != empty(uint256)): + value = value >> 4 + result = unsafe_add(result, 4) + if (value >> 2 != empty(uint256)): + value = value >> 2 + result = unsafe_add(result, 2) + if (value >> 1 != empty(uint256)): + result = unsafe_add(result, 1) + + if ((roundup) and ((1 << result) < x)): + result = unsafe_add(result, 1) + + return result -@external +@internal @pure -def log_10(x: uint256, roundup: bool) -> uint256: +def _log10(x: uint256, roundup: bool) -> uint256: """ @dev Returns the log in base 10 of `x`, following the selected rounding direction. @@ -260,16 +290,16 @@ def log_10(x: uint256, roundup: bool) -> uint256: to round up or not. The default `False` is round down. @return uint256 The 32-byte calculation result. """ - value: uint256 = x - result: uint256 = empty(uint256) - # For the special case `x == 0` we already return 0 here in order # not to iterate through the remaining code. if (x == empty(uint256)): return empty(uint256) + value: uint256 = x + result: uint256 = empty(uint256) + # The following lines cannot overflow because we have the well-known - # decay behaviour of `log_10(max_value(uint256)) < max_value(uint256)`. + # decay behaviour of `log10(max_value(uint256)) < max_value(uint256)`. if (x >= 10 ** 64): value = unsafe_div(x, 10 ** 64) result = 64 @@ -291,15 +321,15 @@ def log_10(x: uint256, roundup: bool) -> uint256: if (value >= 10): result = unsafe_add(result, 1) - if (roundup and (10 ** result < x)): + if ((roundup) and (10 ** result < x)): result = unsafe_add(result, 1) return result -@external +@internal @pure -def log_256(x: uint256, roundup: bool) -> uint256: +def _log256(x: uint256, roundup: bool) -> uint256: """ @dev Returns the log in base 256 of `x`, following the selected rounding direction. @@ -313,16 +343,16 @@ def log_256(x: uint256, roundup: bool) -> uint256: to round up or not. The default `False` is round down. @return uint256 The 32-byte calculation result. """ - value: uint256 = x - result: uint256 = empty(uint256) - # For the special case `x == 0` we already return 0 here in order # not to iterate through the remaining code. if (x == empty(uint256)): return empty(uint256) + value: uint256 = x + result: uint256 = empty(uint256) + # The following lines cannot overflow because we have the well-known - # decay behaviour of `log_256(max_value(uint256)) < max_value(uint256)`. + # decay behaviour of `log256(max_value(uint256)) < max_value(uint256)`. if (x >> 128 != empty(uint256)): value = x >> 128 result = 16 @@ -338,15 +368,15 @@ def log_256(x: uint256, roundup: bool) -> uint256: if (value >> 8 != empty(uint256)): result = unsafe_add(result, 1) - if (roundup and ((1 << (result << 3)) < x)): + if ((roundup) and ((1 << (result << 3)) < x)): result = unsafe_add(result, 1) return result -@external +@internal @pure -def wad_ln(x: int256) -> int256: +def _wad_ln(x: int256) -> int256: """ @dev Calculates the natural logarithm of a signed integer with a precision of 1e18. @@ -358,15 +388,15 @@ def wad_ln(x: int256) -> int256: @param x The 32-byte variable. @return int256 The 32-byte calculation result. """ - value: int256 = x - - assert x >= empty(int256), "Math: wad_ln undefined" + assert x >= empty(int256), "math: wad_ln undefined" # For the special case `x == 0` we already return 0 here in order # not to iterate through the remaining code. if (x == empty(int256)): return empty(int256) + value: int256 = x + # We want to convert `x` from "10 ** 18" fixed point to "2 ** 96" # fixed point. We do this by multiplying by "2 ** 96 / 10 ** 18". # But since "ln(x * C) = ln(x) + ln(C)" holds, we can just do nothing @@ -374,7 +404,7 @@ def wad_ln(x: int256) -> int256: # Reduce the range of `x` to "(1, 2) * 2 ** 96". # Also remember that "ln(2 ** k * x) = k * ln(2) + ln(x)" holds. - k: int256 = unsafe_sub(convert(self._log_2(convert(x, uint256), False), int256), 96) + k: int256 = unsafe_sub(convert(self._log2(convert(x, uint256), False), int256), 96) # Note that to circumvent Vyper's safecast feature for the potentially # negative expression `value <<= uint256(159 - k)`, we first convert the # expression `value <<= uint256(159 - k)` to `bytes32` and subsequently @@ -417,9 +447,9 @@ def wad_ln(x: int256) -> int256: 600_920_179_829_731_861_736_702_779_321_621_459_595_472_258_049_074_101_567_377_883_020_018_308) >> 174 -@external +@internal @pure -def wad_exp(x: int256) -> int256: +def _wad_exp(x: int256) -> int256: """ @dev Calculates the natural exponential function of a signed integer with a precision of 1e18. @@ -438,7 +468,7 @@ def wad_exp(x: int256) -> int256: # When the result is "> (2 ** 255 - 1) / 1e18" we cannot represent it as a signed integer. # This happens when "x >= floor(log((2 ** 255 - 1) / 1e18) * 1e18) ~ 135". - assert x < 135_305_999_368_893_231_589, "Math: wad_exp overflow" + assert x < 135_305_999_368_893_231_589, "math: wad_exp overflow" # `x` is now in the range "(-42, 136) * 1e18". Convert to "(-42, 136) * 2 ** 96" for higher # intermediate precision and a binary base. This base conversion is a multiplication with @@ -485,9 +515,9 @@ def wad_exp(x: int256) -> int256: convert(unsafe_sub(195, k), uint256), int256) -@external +@internal @pure -def cbrt(x: uint256, roundup: bool) -> uint256: +def _cbrt(x: uint256, roundup: bool) -> uint256: """ @dev Calculates the cube root of an unsigned integer. @notice Note that this function consumes about 1,600 to 1,800 gas units @@ -506,15 +536,15 @@ def cbrt(x: uint256, roundup: bool) -> uint256: y: uint256 = unsafe_div(self._wad_cbrt(x), 10 ** 12) - if (roundup and (unsafe_mul(unsafe_mul(y, y), y) != x)): + if ((roundup) and (unsafe_mul(unsafe_mul(y, y), y) != x)): y = unsafe_add(y, 1) return y -@external +@internal @pure -def wad_cbrt(x: uint256) -> uint256: +def _wad_cbrt(x: uint256) -> uint256: """ @dev Calculates the cube root of an unsigned integer with a precision of 1e18. @@ -530,71 +560,6 @@ def wad_cbrt(x: uint256) -> uint256: if (x == empty(uint256)): return empty(uint256) - return self._wad_cbrt(x) - - -@internal -@pure -def _log_2(x: uint256, roundup: bool) -> uint256: - """ - @dev An `internal` helper function that returns the log in base 2 - of `x`, following the selected rounding direction. - @notice Note that it returns 0 if given 0. The implementation is - inspired by OpenZeppelin's implementation here: - https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol. - @param x The 32-byte variable. - @param roundup The Boolean variable that specifies whether - to round up or not. The default `False` is round down. - @return uint256 The 32-byte calculation result. - """ - value: uint256 = x - result: uint256 = empty(uint256) - - # The following lines cannot overflow because we have the well-known - # decay behaviour of `log_2(max_value(uint256)) < max_value(uint256)`. - if (x >> 128 != empty(uint256)): - value = x >> 128 - result = 128 - if (value >> 64 != empty(uint256)): - value = value >> 64 - result = unsafe_add(result, 64) - if (value >> 32 != empty(uint256)): - value = value >> 32 - result = unsafe_add(result, 32) - if (value >> 16 != empty(uint256)): - value = value >> 16 - result = unsafe_add(result, 16) - if (value >> 8 != empty(uint256)): - value = value >> 8 - result = unsafe_add(result, 8) - if (value >> 4 != empty(uint256)): - value = value >> 4 - result = unsafe_add(result, 4) - if (value >> 2 != empty(uint256)): - value = value >> 2 - result = unsafe_add(result, 2) - if (value >> 1 != empty(uint256)): - result = unsafe_add(result, 1) - - if (roundup and ((1 << result) < x)): - result = unsafe_add(result, 1) - - return result - - -@internal -@pure -def _wad_cbrt(x: uint256) -> uint256: - """ - @dev An `internal` helper function that calculates the cube root of an - unsigned integer with a precision of 1e18. - @notice Note that this function consumes about 1,450 to 1,650 gas units - depending on the value of `x`. The implementation is inspired - by Curve Finance's implementation under the MIT license here: - https://github.com/curvefi/tricrypto-ng/blob/main/contracts/main/CurveCryptoMathOptimized3.vy. - @param x The 32-byte variable from which the cube root is calculated. - @return The 32-byte cubic root of `x` with a precision of 1e18. - """ # Since this cube root is for numbers with base 1e18, we have to scale # the input by 1e36 to increase the precision. This leads to an overflow # for very large numbers. So we conditionally sacrifice precision. @@ -607,7 +572,7 @@ def _wad_cbrt(x: uint256) -> uint256: value = unsafe_mul(x, 10 ** 36) # Compute the binary logarithm of `value`. - log2x: uint256 = self._log_2(value, False) + log2x: uint256 = self._log2(value, False) # If we divide log2x by 3, the remainder is "log2x % 3". So if we simply # multiply "2 ** (log2x/3)" and discard the remainder to calculate our guess, @@ -640,5 +605,5 @@ def _wad_cbrt(x: uint256) -> uint256: return unsafe_mul(y, 10 ** 12) elif (x >= unsafe_div(max_value(uint256), 10 ** 36)): return unsafe_mul(y, 10 ** 6) - else: - return y + + return y diff --git a/src/snekmate/utils/MerkleProofVerification.vy b/src/snekmate/utils/merkle_proof_verification.vy similarity index 86% rename from src/snekmate/utils/MerkleProofVerification.vy rename to src/snekmate/utils/merkle_proof_verification.vy index 9d585751..bcc8a463 100644 --- a/src/snekmate/utils/MerkleProofVerification.vy +++ b/src/snekmate/utils/merkle_proof_verification.vy @@ -1,7 +1,7 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Merkle Tree Proof Verification Functions -@custom:contract-name MerkleProofVerification +@custom:contract-name merkle_proof_verification @license GNU Affero General Public License v3.0 only @author pcaversaccio @notice The Merkle tree and the corresponding proofs can be generated @@ -18,7 +18,7 @@ reinterpreted as a leaf value. OpenZeppelin's JavaScript library `merkle-tree` (https://github.com/OpenZeppelin/merkle-tree) generates Merkle trees that are safe against this attack out of - the box. You will find a quick start guide in the README. + the box. You will find a quick start guide in the `README`. OpenZeppelin provides some good examples of how to construct Merkle tree proofs correctly: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/utils/cryptography/MerkleProof.test.js. @@ -33,7 +33,11 @@ """ -@external +# @dev Stores the 1-byte upper bound for the dynamic arrays. +_DYNARRAY_BOUND: constant(uint8) = max_value(uint8) + + +@deploy @payable def __init__(): """ @@ -44,9 +48,9 @@ def __init__(): pass -@external +@internal @pure -def verify(proof: DynArray[bytes32, max_value(uint16)], root: bytes32, leaf: bytes32) -> bool: +def _verify(proof: DynArray[bytes32, _DYNARRAY_BOUND], root: bytes32, leaf: bytes32) -> bool: """ @dev Returns `True` if it can be proved that a `leaf` is part of a Merkle tree defined by `root`. @@ -63,10 +67,10 @@ def verify(proof: DynArray[bytes32, max_value(uint16)], root: bytes32, leaf: byt return self._process_proof(proof, leaf) == root -@external +@internal @pure -def multi_proof_verify(proof: DynArray[bytes32, max_value(uint16)], proof_flags: DynArray[bool, max_value(uint16)], - root: bytes32, leaves: DynArray[bytes32, max_value(uint16)]) -> bool: +def _multi_proof_verify(proof: DynArray[bytes32, _DYNARRAY_BOUND], proof_flags: DynArray[bool, _DYNARRAY_BOUND], + root: bytes32, leaves: DynArray[bytes32, _DYNARRAY_BOUND]) -> bool: """ @dev Returns `True` if it can be simultaneously proved that `leaves` are part of a Merkle tree defined by `root` @@ -90,7 +94,7 @@ def multi_proof_verify(proof: DynArray[bytes32, max_value(uint16)], proof_flags: @internal @pure -def _process_proof(proof: DynArray[bytes32, max_value(uint16)], leaf: bytes32) -> bytes32: +def _process_proof(proof: DynArray[bytes32, _DYNARRAY_BOUND], leaf: bytes32) -> bytes32: """ @dev Returns the recovered hash obtained by traversing a Merkle tree from `leaf` using `proof`. @@ -104,15 +108,15 @@ def _process_proof(proof: DynArray[bytes32, max_value(uint16)], leaf: bytes32) - and `proof`. """ computed_hash: bytes32 = leaf - for i in proof: - computed_hash = self._hash_pair(computed_hash, i) + for proof_element: bytes32 in proof: + computed_hash = self._hash_pair(computed_hash, proof_element) return computed_hash @internal @pure -def _process_multi_proof(proof: DynArray[bytes32, max_value(uint16)], proof_flags: DynArray[bool, max_value(uint16)], - leaves: DynArray[bytes32, max_value(uint16)]) -> bytes32: +def _process_multi_proof(proof: DynArray[bytes32, _DYNARRAY_BOUND], proof_flags: DynArray[bool, _DYNARRAY_BOUND], + leaves: DynArray[bytes32, _DYNARRAY_BOUND]) -> bytes32: """ @dev Returns the recovered hash obtained by traversing a Merkle tree from `leaves` using `proof` and a @@ -150,12 +154,12 @@ def _process_multi_proof(proof: DynArray[bytes32, max_value(uint16)], proof_flag # Checks the validity of the proof. We do not check for an # overflow (nor underflow) as `leaves_length`, `proof`, and - # `total_hashes` are bounded by the value `max_value(uint16)` + # `total_hashes` are bounded by the value `max_value(uint8)` # and therefore cannot overflow the `uint256` type when they - # are added together or incremented by 1. - assert unsafe_add(leaves_length, len(proof)) == unsafe_add(total_hashes, 1), "MerkleProof: invalid multiproof" + # are added together or incremented by `1`. + assert unsafe_add(leaves_length, len(proof)) == unsafe_add(total_hashes, 1), "merkle_proof_verification: invalid multiproof" - hashes: DynArray[bytes32, max_value(uint16)] = [] + hashes: DynArray[bytes32, _DYNARRAY_BOUND] = [] leaf_pos: uint256 = empty(uint256) hash_pos: uint256 = empty(uint256) proof_pos: uint256 = empty(uint256) @@ -167,7 +171,7 @@ def _process_multi_proof(proof: DynArray[bytes32, max_value(uint16)], proof_flag # the next leaf is picked up, otherwise the next hash. # - depending on the flag, either another value from the "main queue" # (merging branches) or an element from the `proof` array. - for flag in proof_flags: + for flag: bool in proof_flags: if (leaf_pos < leaves_length): a = leaves[leaf_pos] leaf_pos = unsafe_add(leaf_pos, 1) @@ -193,8 +197,8 @@ def _process_multi_proof(proof: DynArray[bytes32, max_value(uint16)], proof_flag return hashes[unsafe_sub(total_hashes, 1)] elif (leaves_length != empty(uint256)): return leaves[empty(uint256)] - else: - return proof[empty(uint256)] + + return proof[empty(uint256)] @internal @@ -210,5 +214,5 @@ def _hash_pair(a: bytes32, b: bytes32) -> bytes32: """ if (convert(a, uint256) < convert(b, uint256)): return keccak256(concat(a, b)) - else: - return keccak256(concat(b, a)) + + return keccak256(concat(b, a)) diff --git a/src/snekmate/utils/message_hash_utils.vy b/src/snekmate/utils/message_hash_utils.vy new file mode 100644 index 00000000..247b942e --- /dev/null +++ b/src/snekmate/utils/message_hash_utils.vy @@ -0,0 +1,94 @@ +# pragma version ~=0.4.0rc6 +""" +@title Signature Message Hash Utility Functions +@custom:contract-name message_hash_utils +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +@notice These functions can be used to generate message hashes that conform + to the EIP-191 (https://eips.ethereum.org/EIPS/eip-191) as well as + EIP-712 (https://eips.ethereum.org/EIPS/eip-712) specifications. The + implementation is inspired by OpenZeppelin's implementation here: + https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MessageHashUtils.sol. +""" + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@internal +@pure +def _to_eth_signed_message_hash(hash: bytes32) -> bytes32: + """ + @dev Returns an Ethereum signed message from a 32-byte + message digest `hash`. + @notice This function returns a 32-byte hash that + corresponds to the one signed with the JSON-RPC method: + https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign. + This method is part of EIP-191: + https://eips.ethereum.org/EIPS/eip-191. + @param hash The 32-byte message digest. + @return bytes32 The 32-byte Ethereum signed message. + """ + return keccak256(concat(b"\x19Ethereum Signed Message:\n32", hash)) + + +@internal +@view +def _to_data_with_intended_validator_hash_self(data: Bytes[1_024]) -> bytes32: + """ + @dev Returns an Ethereum signed data with this contract + as the intended validator and a maximum 1,024-byte + payload `data`. + @notice This function structures the data according to + the version `0x00` of EIP-191: + https://eips.ethereum.org/EIPS/eip-191#version-0x00. + @param data The maximum 1,024-byte data to be signed. + @return bytes32 The 32-byte Ethereum signed data. + """ + return self._to_data_with_intended_validator_hash(self, data) + + +@internal +@pure +def _to_data_with_intended_validator_hash(validator: address, data: Bytes[1_024]) -> bytes32: + """ + @dev Returns an Ethereum signed data with `validator` as + the intended validator and a maximum 1,024-byte payload + `data`. + @notice This function structures the data according to + the version `0x00` of EIP-191: + https://eips.ethereum.org/EIPS/eip-191#version-0x00. + @param validator The 20-byte intended validator address. + @param data The maximum 1,024-byte data to be signed. + @return bytes32 The 32-byte Ethereum signed data. + """ + return keccak256(concat(b"\x19\x00", convert(validator, bytes20), data)) + + +@internal +@pure +def _to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32: + """ + @dev Returns an Ethereum signed typed data from a 32-byte + `domain_separator` and a 32-byte `struct_hash`. + @notice This function returns a 32-byte hash that + corresponds to the one signed with the JSON-RPC method: + https://eips.ethereum.org/EIPS/eip-712#specification-of-the-eth_signtypeddata-json-rpc. + This method is part of EIP-712: + https://eips.ethereum.org/EIPS/eip-712. + @param domain_separator The 32-byte domain separator that is + used as part of the EIP-712 encoding scheme. + @param struct_hash The 32-byte struct hash that is used as + part of the EIP-712 encoding scheme. See the definition: + https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. + @return bytes32 The 32-byte Ethereum signed typed data. + """ + return keccak256(concat(b"\x19\x01", domain_separator, struct_hash)) diff --git a/src/snekmate/utils/mocks/base64_mock.vy b/src/snekmate/utils/mocks/base64_mock.vy new file mode 100644 index 00000000..2ac92fb6 --- /dev/null +++ b/src/snekmate/utils/mocks/base64_mock.vy @@ -0,0 +1,75 @@ +# pragma version ~=0.4.0rc6 +""" +@title `base64` Module Reference Implementation +@custom:contract-name base64_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `base64` module. +# @notice Please note that the `base64` module +# is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import base64 as b64 + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@pure +def encode(data: Bytes[b64._DATA_INPUT_BOUND], base64_url: bool) -> DynArray[String[4], b64._DATA_OUTPUT_BOUND]: + """ + @dev Encodes a `Bytes` array using the Base64 + binary-to-text encoding scheme. + @notice Due to the Vyper design with fixed-size + string parameters, string concatenations + with itself in a loop can lead to length + mismatches (the underlying issue is that + Vyper does not support a mutable `Bytes` + type). To circumvent this issue, we choose + a dynamic array as the return type. + @param data The maximum 1,024-byte data to be + Base64-encoded. + @param base64_url The Boolean variable that specifies + whether to use a URL and filename-safe alphabet + or not. + @return DynArray The maximum 4-character user-readable + string array that combined results in the Base64 + encoding of `data`. + """ + return b64._encode(data, base64_url) + + +@external +@pure +def decode(data: String[b64._DATA_OUTPUT_BOUND], base64_url: bool) -> DynArray[Bytes[3], b64._DATA_INPUT_BOUND]: + """ + @dev Decodes a `String` input using the Base64 + binary-to-text encoding scheme. + @notice Due to the Vyper design with fixed-size + byte parameters, byte concatenations + with itself in a loop can lead to length + mismatches (the underlying issue is that + Vyper does not support a mutable `Bytes` + type). To circumvent this issue, we choose + a dynamic array as the return type. Note + that line breaks are not supported. + @param data The maximum 1,368-byte data to be + Base64-decoded. + @param base64_url The Boolean variable that specifies + whether to use a URL and filename-safe alphabet + or not. + @return DynArray The maximum 3-byte array that combined + results in the Base64 decoding of `data`. + """ + return b64._decode(data, base64_url) diff --git a/src/snekmate/utils/mocks/batch_distributor_mock.vy b/src/snekmate/utils/mocks/batch_distributor_mock.vy new file mode 100644 index 00000000..14308b26 --- /dev/null +++ b/src/snekmate/utils/mocks/batch_distributor_mock.vy @@ -0,0 +1,70 @@ +# pragma version ~=0.4.0rc6 +""" +@title `batch_distributor` Module Reference Implementation +@custom:contract-name batch_distributor_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and initialise the `batch_distributor` module. +from .. import batch_distributor as bd +initializes: bd + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + bd.__init__() + + +@external +@payable +def distribute_ether(data: bd.Batch): + """ + @dev Distributes ether, denominated in wei, to a + predefined batch of recipient addresses. + @notice In the event that excessive ether is sent, + the residual amount is returned back to the + `msg.sender`. Please note that you must add the + `payable` decorator to any `external` function + that calls the `internal` function `_distribute_ether` + to enable the handling of ether. + + Furthermore, it is important to note that an + external call via `raw_call` does not perform + an external code size check on the target address. + @param data Nested struct object that contains an array + of tuples that contain each a recipient address & + ether amount in wei. + """ + bd._distribute_ether(data) + + +@external +def distribute_token(token: bd.IERC20, data: bd.Batch): + """ + @dev Distributes ERC-20 tokens, denominated in their corresponding + lowest unit, to a predefined batch of recipient addresses. + @notice To deal with (potentially) non-compliant ERC-20 tokens that do have + no return value, we use the kwarg `default_return_value` for external + calls. This function was introduced in Vyper version `0.3.4`. For more + details see: + - https://github.com/vyperlang/vyper/pull/2839, + - https://github.com/vyperlang/vyper/issues/2812, + - https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca. + Note: Since we cast the token address into the official ERC-20 interface, + the use of non-compliant ERC-20 tokens is prevented by design. Nevertheless, + we keep this guardrail for security reasons. + @param token The ERC-20 compatible (i.e. ERC-777 is also + viable) token contract address. + @param data Nested struct object that contains an array + of tuples that contain each a recipient address & + token amount. + """ + bd._distribute_token(token, data) diff --git a/src/snekmate/utils/mocks/create2_address_mock.vy b/src/snekmate/utils/mocks/create2_address_mock.vy new file mode 100644 index 00000000..03300152 --- /dev/null +++ b/src/snekmate/utils/mocks/create2_address_mock.vy @@ -0,0 +1,60 @@ +# pragma version ~=0.4.0rc6 +""" +@title `create2_address` Module Reference Implementation +@custom:contract-name create2_address_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `create2_address` module. +# @notice Please note that the `create2_address` +# module is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import create2_address as c2a + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@view +def compute_address_self(salt: bytes32, bytecode_hash: bytes32) -> address: + """ + @dev Returns the address where a contract will be stored if + deployed via this contract using the `CREATE2` opcode. + Any change in the `bytecode_hash` or `salt` values will + result in a new destination address. + @param salt The 32-byte random value used to create the contract + address. + @param bytecode_hash The 32-byte bytecode digest of the contract + creation bytecode. + @return address The 20-byte address where a contract will be stored. + """ + return c2a._compute_address_self(salt, bytecode_hash) + + +@external +@pure +def compute_address(salt: bytes32, bytecode_hash: bytes32, deployer: address) -> address: + """ + @dev Returns the address where a contract will be stored if + deployed via `deployer` using the `CREATE2` opcode. + Any change in the `bytecode_hash` or `salt` values will + result in a new destination address. + @param salt The 32-byte random value used to create the contract + address. + @param bytecode_hash The 32-byte bytecode digest of the contract + creation bytecode. + @param deployer The 20-byte deployer address. + @return address The 20-byte address where a contract will be stored. + """ + return c2a._compute_address(salt, bytecode_hash, deployer) diff --git a/src/snekmate/utils/mocks/create_address_mock.vy b/src/snekmate/utils/mocks/create_address_mock.vy new file mode 100644 index 00000000..4933ea22 --- /dev/null +++ b/src/snekmate/utils/mocks/create_address_mock.vy @@ -0,0 +1,61 @@ +# pragma version ~=0.4.0rc6 +""" +@title `create_address` Module Reference Implementation +@custom:contract-name create_address_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `create_address` module. +# @notice Please note that the `create_address` +# module is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import create_address as ca + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@view +def compute_address_rlp_self(nonce: uint256) -> address: + """ + @dev Returns the address where a contract will be stored if + deployed via this contract using the `CREATE` opcode. + @param nonce The 32-byte account nonce of this contract. + @return address The 20-byte address where a contract will be stored. + """ + return ca._compute_address_rlp_self(nonce) + + +@external +@pure +def compute_address_rlp(deployer: address, nonce: uint256) -> address: + """ + @dev Returns the address where a contract will be stored + if deployed via `deployer` using the `CREATE` opcode. + For the specification of the Recursive Length Prefix (RLP) + encoding scheme, please refer to p. 19 of the Ethereum + Yellow Paper (https://ethereum.github.io/yellowpaper/paper.pdf) + and the Ethereum Wiki (https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp). + For further insights also, see the following issue: + https://github.com/transmissions11/solmate/issues/207. + + Based on the EIP-161 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md) + specification, all contract accounts on the Ethereum mainnet + are initiated with `nonce = 1`. Thus, the first contract address + created by another contract is calculated with a non-zero nonce. + @param deployer The 20-byte deployer address. + @param nonce The 32-byte account nonce of the deployer address. + @return address The 20-byte address where a contract will be stored. + """ + return ca._compute_address_rlp(deployer, nonce) diff --git a/src/snekmate/utils/mocks/ecdsa_mock.vy b/src/snekmate/utils/mocks/ecdsa_mock.vy new file mode 100644 index 00000000..96802ec1 --- /dev/null +++ b/src/snekmate/utils/mocks/ecdsa_mock.vy @@ -0,0 +1,50 @@ +# pragma version ~=0.4.0rc6 +""" +@title `ecdsa` Module Reference Implementation +@custom:contract-name ecdsa_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `ecdsa` module. +# @notice Please note that the `ecdsa` module +# is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import ecdsa as ec + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@pure +def recover_sig(hash: bytes32, signature: Bytes[65]) -> address: + """ + @dev Recovers the signer address from a message digest `hash` + and the signature `signature`. + @notice WARNING: This function is vulnerable to a kind of + signature malleability due to accepting EIP-2098 + compact signatures in addition to the traditional + 65-byte signature format. The potentially affected + contracts are those that implement signature reuse + or replay protection by marking the signature itself + as used rather than the signed message or a nonce + included in it. A user may take a signature that has + already been submitted, submit it again in a different + form, and bypass this protection. Also, see OpenZeppelin's + security advisory for more information: + https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h. + @param hash The 32-byte message digest that was signed. + @param signature The secp256k1 64/65-byte signature of `hash`. + @return address The recovered 20-byte signer address. + """ + return ec._recover_sig(hash, signature) diff --git a/src/snekmate/utils/mocks/eip712_domain_separator_mock.vy b/src/snekmate/utils/mocks/eip712_domain_separator_mock.vy new file mode 100644 index 00000000..9580b69a --- /dev/null +++ b/src/snekmate/utils/mocks/eip712_domain_separator_mock.vy @@ -0,0 +1,76 @@ +# pragma version ~=0.4.0rc6 +""" +@title `eip712_domain_separator` Module Reference Implementation +@custom:contract-name eip712_domain_separator_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import and implement the `IERC5267` interface, +# which is written using standard Vyper syntax. +from ..interfaces import IERC5267 +implements: IERC5267 + + +# @dev We import and initialise the `eip712_domain_separator` module. +from .. import eip712_domain_separator as ed +initializes: ed + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) the `external` function +# `eip712Domain` from the `eip712_domain_separator` module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: ed.eip712Domain + + +@deploy +@payable +def __init__(name_: String[50], version_: String[20]): + """ + @dev Initialises the domain separator and the parameter caches. + To omit the opcodes for checking the `msg.value` in the + creation-time EVM bytecode, the constructor is declared as + `payable`. + @notice The definition of the domain separator can be found here: + https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator. + Since the Vyper design requires strings of fixed size, + we arbitrarily set the maximum length for `name` to 50 + characters and `version` to 20 characters. + @param name_ The maximum 50-character user-readable string name + of the signing domain, i.e. the name of the dApp or protocol. + @param version_ The maximum 20-character current main version of + the signing domain. Signatures from different versions are + not compatible. + """ + ed.__init__(name_, version_) + + +@external +@view +def domain_separator_v4() -> bytes32: + """ + @dev Returns the domain separator for the current chain. + @return bytes32 The 32-byte domain separator. + """ + return ed._domain_separator_v4() + + +@external +@view +def hash_typed_data_v4(struct_hash: bytes32) -> bytes32: + """ + @dev Returns the hash of the fully encoded EIP-712 + message for this domain. + @notice The definition of the hashed struct can be found here: + https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. + @param struct_hash The 32-byte hashed struct. + @return bytes32 The 32-byte fully encoded EIP712 + message hash for this domain. + """ + return ed._hash_typed_data_v4(struct_hash) diff --git a/src/snekmate/utils/mocks/math_mock.vy b/src/snekmate/utils/mocks/math_mock.vy new file mode 100644 index 00000000..6257b3d3 --- /dev/null +++ b/src/snekmate/utils/mocks/math_mock.vy @@ -0,0 +1,229 @@ +# pragma version ~=0.4.0rc6 +""" +@title `math` Module Reference Implementation +@custom:contract-name math_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `math` module. +# @notice Please note that the `math` module +# is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import math as ma + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@pure +def uint256_average(x: uint256, y: uint256) -> uint256: + """ + @dev Returns the average of two 32-byte unsigned integers. + @notice Note that the result is rounded towards zero. For + more details on finding the average of two unsigned + integers without an overflow, please refer to: + https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223. + @param x The first 32-byte unsigned integer of the data set. + @param y The second 32-byte unsigned integer of the data set. + @return uint256 The 32-byte average (rounded towards zero) of + `x` and `y`. + """ + return ma._uint256_average(x, y) + + +@external +@pure +def int256_average(x: int256, y: int256) -> int256: + """ + @dev Returns the average of two 32-byte signed integers. + @notice Note that the result is rounded towards infinity. + For more details on finding the average of two signed + integers without an overflow, please refer to: + https://patents.google.com/patent/US6007232A/en. + @param x The first 32-byte signed integer of the data set. + @param y The second 32-byte signed integer of the data set. + @return int256 The 32-byte average (rounded towards infinity) + of `x` and `y`. + """ + return ma._int256_average(x, y) + + +@external +@pure +def ceil_div(x: uint256, y: uint256) -> uint256: + """ + @dev Calculates "ceil(x / y)" for any strictly positive `y`. + @notice The implementation is inspired by OpenZeppelin's + implementation here: + https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol. + @param x The 32-byte numerator. + @param y The 32-byte denominator. + @return uint256 The 32-byte rounded up result of "x/y". + """ + return ma._ceil_div(x, y) + + +@external +@pure +def signum(x: int256) -> int256: + """ + @dev Returns the indication of the sign of a 32-byte signed integer. + @notice The function returns `-1` if `x < 0`, `0` if `x == 0`, and `1` + if `x > 0`. For more details on finding the sign of a signed + integer, please refer to: + https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign. + @param x The 32-byte signed integer variable. + @return int256 The 32-byte sign indication (`1`, `0`, or `-1`) of `x`. + """ + return ma._signum(x) + + +@external +@pure +def mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint256: + """ + @dev Calculates "(x * y) / denominator" in 512-bit precision, + following the selected rounding direction. + @notice The implementation is inspired by Remco Bloemen's + implementation under the MIT license here: + https://xn--2-umb.com/21/muldiv. + Furthermore, the rounding direction design pattern is + inspired by OpenZeppelin's implementation here: + https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol. + @param x The 32-byte multiplicand. + @param y The 32-byte multiplier. + @param denominator The 32-byte divisor. + @param roundup The Boolean variable that specifies whether + to round up or not. The default `False` is round down. + @return uint256 The 32-byte calculation result. + """ + return ma._mul_div(x, y, denominator, roundup) + + +@external +@pure +def log2(x: uint256, roundup: bool) -> uint256: + """ + @dev Returns the log in base 2 of `x`, following the selected + rounding direction. + @notice Note that it returns 0 if given 0. The implementation is + inspired by OpenZeppelin's implementation here: + https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol. + @param x The 32-byte variable. + @param roundup The Boolean variable that specifies whether + to round up or not. The default `False` is round down. + @return uint256 The 32-byte calculation result. + """ + return ma._log2(x, roundup) + + +@external +@pure +def log10(x: uint256, roundup: bool) -> uint256: + """ + @dev Returns the log in base 10 of `x`, following the selected + rounding direction. + @notice Note that it returns 0 if given 0. The implementation is + inspired by OpenZeppelin's implementation here: + https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol. + @param x The 32-byte variable. + @param roundup The Boolean variable that specifies whether + to round up or not. The default `False` is round down. + @return uint256 The 32-byte calculation result. + """ + return ma._log10(x, roundup) + + +@external +@pure +def log256(x: uint256, roundup: bool) -> uint256: + """ + @dev Returns the log in base 256 of `x`, following the selected + rounding direction. + @notice Note that it returns 0 if given 0. Also, adding one to the + rounded down result gives the number of pairs of hex symbols + needed to represent `x` as a hex string. The implementation is + inspired by OpenZeppelin's implementation here: + https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol. + @param x The 32-byte variable. + @param roundup The Boolean variable that specifies whether + to round up or not. The default `False` is round down. + @return uint256 The 32-byte calculation result. + """ + return ma._log256(x, roundup) + + +@external +@pure +def wad_ln(x: int256) -> int256: + """ + @dev Calculates the natural logarithm of a signed integer with a + precision of 1e18. + @notice Note that it returns 0 if given 0. Furthermore, this function + consumes about 1,400 to 1,650 gas units depending on the value + of `x`. The implementation is inspired by Remco Bloemen's + implementation under the MIT license here: + https://xn--2-umb.com/22/exp-ln. + @param x The 32-byte variable. + @return int256 The 32-byte calculation result. + """ + return ma._wad_ln(x) + + +@external +@pure +def wad_exp(x: int256) -> int256: + """ + @dev Calculates the natural exponential function of a signed integer with + a precision of 1e18. + @notice Note that this function consumes about 810 gas units. The implementation + is inspired by Remco Bloemen's implementation under the MIT license here: + https://xn--2-umb.com/22/exp-ln. + @param x The 32-byte variable. + @return int256 The 32-byte calculation result. + """ + return ma._wad_exp(x) + + +@external +@pure +def cbrt(x: uint256, roundup: bool) -> uint256: + """ + @dev Calculates the cube root of an unsigned integer. + @notice Note that this function consumes about 1,600 to 1,800 gas units + depending on the value of `x` and `roundup`. The implementation is + inspired by Curve Finance's implementation under the MIT license here: + https://github.com/curvefi/tricrypto-ng/blob/main/contracts/main/CurveCryptoMathOptimized3.vy. + @param x The 32-byte variable from which the cube root is calculated. + @param roundup The Boolean variable that specifies whether + to round up or not. The default `False` is round down. + @return The 32-byte cube root of `x`. + """ + return ma._cbrt(x, roundup) + + +@external +@pure +def wad_cbrt(x: uint256) -> uint256: + """ + @dev Calculates the cube root of an unsigned integer with a precision + of 1e18. + @notice Note that this function consumes about 1,500 to 1,700 gas units + depending on the value of `x`. The implementation is inspired + by Curve Finance's implementation under the MIT license here: + https://github.com/curvefi/tricrypto-ng/blob/main/contracts/main/CurveCryptoMathOptimized3.vy. + @param x The 32-byte variable from which the cube root is calculated. + @return The 32-byte cubic root of `x` with a precision of 1e18. + """ + return ma._wad_cbrt(x) diff --git a/src/snekmate/utils/mocks/merkle_proof_verification_mock.vy b/src/snekmate/utils/mocks/merkle_proof_verification_mock.vy new file mode 100644 index 00000000..d3f8221d --- /dev/null +++ b/src/snekmate/utils/mocks/merkle_proof_verification_mock.vy @@ -0,0 +1,70 @@ +# pragma version ~=0.4.0rc6 +""" +@title `merkle_proof_verification` Module Reference Implementation +@custom:contract-name merkle_proof_verification_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `merkle_proof_verification` module. +# @notice Please note that the `merkle_proof_verification` +# module is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import merkle_proof_verification as mp + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@pure +def verify(proof: DynArray[bytes32, mp._DYNARRAY_BOUND], root: bytes32, leaf: bytes32) -> bool: + """ + @dev Returns `True` if it can be proved that a `leaf` is + part of a Merkle tree defined by `root`. + @notice Each pair of leaves and each pair of pre-images + are assumed to be sorted. + @param proof The 32-byte array containing sibling hashes + on the branch from the `leaf` to the `root` of the + Merkle tree. + @param root The 32-byte Merkle root hash. + @param leaf The 32-byte leaf hash. + @return bool The verification whether `leaf` is part of + a Merkle tree defined by `root`. + """ + return mp._verify(proof, root, leaf) + + +@external +@pure +def multi_proof_verify(proof: DynArray[bytes32, mp._DYNARRAY_BOUND], proof_flags: DynArray[bool, mp._DYNARRAY_BOUND], + root: bytes32, leaves: DynArray[bytes32, mp._DYNARRAY_BOUND]) -> bool: + """ + @dev Returns `True` if it can be simultaneously proved that + `leaves` are part of a Merkle tree defined by `root` + and a given set of `proof_flags`. + @notice Note that not all Merkle trees allow for multiproofs. + See {merkle_proof_verification-_process_multi_proof} for + further details. + @param proof The 32-byte array containing sibling hashes + on the branches from `leaves` to the `root` of the + Merkle tree. + @param proof_flags The Boolean array of flags indicating + whether another value from the "main queue" (merging + branches) or an element from the `proof` array is used + to calculate the next hash. + @param root The 32-byte Merkle root hash. + @param leaves The 32-byte array containing the leaf hashes. + @return bool The verification whether `leaves` are simultaneously + part of a Merkle tree defined by `root`. + """ + return mp._multi_proof_verify(proof, proof_flags, root, leaves) diff --git a/src/snekmate/utils/mocks/message_hash_utils_mock.vy b/src/snekmate/utils/mocks/message_hash_utils_mock.vy new file mode 100644 index 00000000..da25f9ba --- /dev/null +++ b/src/snekmate/utils/mocks/message_hash_utils_mock.vy @@ -0,0 +1,96 @@ +# pragma version ~=0.4.0rc6 +""" +@title `message_hash_utils` Module Reference Implementation +@custom:contract-name message_hash_utils_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `message_hash_utils` module. +# @notice Please note that the `message_hash_utils` +# module is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import message_hash_utils as mu + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@pure +def to_eth_signed_message_hash(hash: bytes32) -> bytes32: + """ + @dev Returns an Ethereum signed message from a 32-byte + message digest `hash`. + @notice This function returns a 32-byte hash that + corresponds to the one signed with the JSON-RPC method: + https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign. + This method is part of EIP-191: + https://eips.ethereum.org/EIPS/eip-191. + @param hash The 32-byte message digest. + @return bytes32 The 32-byte Ethereum signed message. + """ + return mu._to_eth_signed_message_hash(hash) + + +@external +@view +def to_data_with_intended_validator_hash_self(data: Bytes[1_024]) -> bytes32: + """ + @dev Returns an Ethereum signed data with this contract + as the intended validator and a maximum 1,024-byte + payload `data`. + @notice This function structures the data according to + the version `0x00` of EIP-191: + https://eips.ethereum.org/EIPS/eip-191#version-0x00. + @param data The maximum 1,024-byte data to be signed. + @return bytes32 The 32-byte Ethereum signed data. + """ + return mu._to_data_with_intended_validator_hash(self, data) + + +@external +@pure +def to_data_with_intended_validator_hash(validator: address, data: Bytes[1_024]) -> bytes32: + """ + @dev Returns an Ethereum signed data with `validator` as + the intended validator and a maximum 1,024-byte payload + `data`. + @notice This function structures the data according to + the version `0x00` of EIP-191: + https://eips.ethereum.org/EIPS/eip-191#version-0x00. + @param validator The 20-byte intended validator address. + @param data The maximum 1,024-byte data to be signed. + @return bytes32 The 32-byte Ethereum signed data. + """ + return mu._to_data_with_intended_validator_hash(validator, data) + + +@external +@pure +def to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32: + """ + @dev Returns an Ethereum signed typed data from a 32-byte + `domain_separator` and a 32-byte `struct_hash`. + @notice This function returns a 32-byte hash that + corresponds to the one signed with the JSON-RPC method: + https://eips.ethereum.org/EIPS/eip-712#specification-of-the-eth_signtypeddata-json-rpc. + This method is part of EIP-712: + https://eips.ethereum.org/EIPS/eip-712. + @param domain_separator The 32-byte domain separator that is + used as part of the EIP-712 encoding scheme. + @param struct_hash The 32-byte struct hash that is used as + part of the EIP-712 encoding scheme. See the definition: + https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. + @return bytes32 The 32-byte Ethereum signed typed data. + """ + return mu._to_typed_data_hash(domain_separator, struct_hash) diff --git a/src/snekmate/utils/mocks/multicall_mock.vy b/src/snekmate/utils/mocks/multicall_mock.vy new file mode 100644 index 00000000..a45c804b --- /dev/null +++ b/src/snekmate/utils/mocks/multicall_mock.vy @@ -0,0 +1,97 @@ +# pragma version ~=0.4.0rc6 +""" +@title `multicall` Module Reference Implementation +@custom:contract-name multicall_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `multicall` module. +# @notice Please note that the `multicall` module +# is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import multicall as mc + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +def multicall(data: DynArray[mc.Batch, mc._DYNARRAY_BOUND]) -> DynArray[mc.Result, mc._DYNARRAY_BOUND]: + """ + @dev Aggregates function calls, ensuring that each + function returns successfully if required. + Since this function uses `CALL`, the `msg.sender` + will be the multicall contract itself. + @notice It is important to note that an external call + via `raw_call` does not perform an external code + size check on the target address. + @param data The array of `Batch` structs. + @return DynArray The array of `Result` structs. + """ + return mc._multicall(data) + + +@external +@payable +def multicall_value(data: DynArray[mc.BatchValue, mc._DYNARRAY_BOUND]) -> DynArray[mc.Result, mc._DYNARRAY_BOUND]: + """ + @dev Aggregates function calls with a `msg.value`, + ensuring that each function returns successfully + if required. Since this function uses `CALL`, + the `msg.sender` will be the multicall contract + itself. + @notice It is important to note that an external call + via `raw_call` does not perform an external code + size check on the target address. + @param data The array of `BatchValue` structs. + @return DynArray The array of `Result` structs. + """ + return mc._multicall_value(data) + + +@external +def multicall_self(data: DynArray[mc.BatchSelf, mc._DYNARRAY_BOUND]) -> DynArray[mc.Result, mc._DYNARRAY_BOUND]: + """ + @dev Aggregates function calls using `DELEGATECALL`, + ensuring that each function returns successfully + if required. Since this function uses `DELEGATECALL`, + the `msg.sender` remains the same account that + invoked the function `multicall_self` in the first place. + @notice Developers can include this function in their own + contract so that users can submit multiple function + calls in one transaction. Since the `msg.sender` is + preserved, it's equivalent to sending multiple transactions + from an EOA (externally-owned account, i.e. non-contract account). + + Furthermore, it is important to note that an external + call via `raw_call` does not perform an external code + size check on the target address. + @param data The array of `BatchSelf` structs. + @return DynArray The array of `Result` structs. + """ + return mc._multicall_self(data) + + +@external +@view +def multistaticcall(data: DynArray[mc.Batch, mc._DYNARRAY_BOUND]) -> DynArray[mc.Result, mc._DYNARRAY_BOUND]: + """ + @dev Aggregates static function calls, ensuring that each + function returns successfully if required. + @notice It is important to note that an external call + via `raw_call` does not perform an external code + size check on the target address. + @param data The array of `Batch` structs. + @return DynArray The array of `Result` structs. + """ + return mc._multistaticcall(data) diff --git a/src/snekmate/utils/mocks/p256_mock.vy b/src/snekmate/utils/mocks/p256_mock.vy new file mode 100644 index 00000000..45c92020 --- /dev/null +++ b/src/snekmate/utils/mocks/p256_mock.vy @@ -0,0 +1,43 @@ +# pragma version ~=0.4.0rc6 +""" +@title `p256` Module Reference Implementation +@custom:contract-name p256_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `p256` module. +# @notice Please note that the `p256` module +# is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import p256 as p2 + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@view +def verify_sig(hash: bytes32, r: uint256, s: uint256, qx: uint256, qy: uint256) -> bool: + """ + @dev Verifies the signature of a message digest `hash` + based on the secp256r1 signature parameters `r` and + `s`, and the public key coordinates `qx` and `qy`. + @param hash The 32-byte message digest that was signed. + @param r The secp256r1 32-byte signature parameter `r`. + @param s The secp256r1 32-byte signature parameter `s`. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @return bool The verification whether the signature is + authentic or not. + """ + return p2._verify_sig(hash, r, s, qx, qy) diff --git a/src/snekmate/utils/mocks/signature_checker_mock.vy b/src/snekmate/utils/mocks/signature_checker_mock.vy new file mode 100644 index 00000000..1ad7c811 --- /dev/null +++ b/src/snekmate/utils/mocks/signature_checker_mock.vy @@ -0,0 +1,83 @@ +# pragma version ~=0.4.0rc6 +""" +@title `signature_checker` Module Reference Implementation +@custom:contract-name signature_checker_mock +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +""" + + +# @dev We import the `signature_checker` module. +# @notice Please note that the `signature_checker` +# module is stateless and therefore does not require +# the `initializes` keyword for initialisation. +from .. import signature_checker as sc + + +# @dev We export (i.e. the runtime bytecode exposes these +# functions externally, allowing them to be called using +# the ABI encoding specification) the `external` getter +# function `IERC1271_ISVALIDSIGNATURE_SELECTOR` from the +# `signature_checker` module. +# @notice Please note that you must always also export (if +# required by the contract logic) `public` declared `constant`, +# `immutable`, and state variables, for which Vyper automatically +# generates an `external` getter function for the variable. +exports: sc.IERC1271_ISVALIDSIGNATURE_SELECTOR + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@external +@view +def is_valid_signature_now(signer: address, hash: bytes32, signature: Bytes[65]) -> bool: + """ + @dev Checks if a signature `signature` is valid + for a given `signer` and message digest `hash`. + If the signer is a smart contract, the signature + is validated against that smart contract using + EIP-1271, otherwise it's validated using {ecdsa-_recover_sig}. + @notice Unlike ECDSA signatures, contract signatures + are revocable and the result of this function + can therefore change over time. It could return + `True` in block N and `False` in block N+1 (or the opposite). + @param signer The 20-byte signer address. + @param hash The 32-byte message digest that was signed. + @param signature The maximum 65-byte signature of `hash`. + @return bool The verification whether `signature` is valid + for the provided data. + @custom:security Since we avoid validating ECDSA signatures + when code is deployed at the signer's address, + it is safe if EIP-7377 (https://eips.ethereum.org/EIPS/eip-7377) + should be deployed one day. + """ + return sc._is_valid_signature_now(signer, hash, signature) + + +@external +@view +def is_valid_ERC1271_signature_now(signer: address, hash: bytes32, signature: Bytes[65]) -> bool: + """ + @dev Checks if a signature `signature` is valid + for a given `signer` and message digest `hash`. + The signature is validated using EIP-1271. + @notice Unlike ECDSA signatures, contract signatures + are revocable and the result of this function + can therefore change over time. It could return + `True` in block N and `False` in block N+1 (or the opposite). + @param signer The 20-byte signer address. + @param hash The 32-byte message digest that was signed. + @param signature The maximum 65-byte signature of `hash`. + @return bool The verification whether `signature` is valid + for the provided data. + """ + return sc._is_valid_ERC1271_signature_now(signer, hash, signature) diff --git a/src/snekmate/utils/Multicall.vy b/src/snekmate/utils/multicall.vy similarity index 66% rename from src/snekmate/utils/Multicall.vy rename to src/snekmate/utils/multicall.vy index 9e2581e4..9770b7d1 100644 --- a/src/snekmate/utils/Multicall.vy +++ b/src/snekmate/utils/multicall.vy @@ -1,11 +1,11 @@ -# pragma version ^0.3.10 +# pragma version ~=0.4.0rc6 """ @title Multicall Functions -@custom:contract-name Multicall +@custom:contract-name multicall @license GNU Affero General Public License v3.0 only @author pcaversaccio -@notice These functions can be used to batch together multiple external - function calls into one single external function call. Please note +@notice These functions can be used to batch together multiple `external` + function calls into one single `external` function call. Please note that this contract is written in the most agnostic way possible and users should adjust statically allocatable memory to their specific needs before deploying it: @@ -26,11 +26,15 @@ """ +# @dev Stores the 1-byte upper bound for the dynamic arrays. +_DYNARRAY_BOUND: constant(uint8) = max_value(uint8) + + # @dev Batch struct for ordinary (i.e. `nonpayable`) function calls. struct Batch: target: address allow_failure: bool - call_data: Bytes[max_value(uint16)] + calldata: Bytes[1_024] # @dev Batch struct for `payable` function calls. @@ -38,14 +42,14 @@ struct BatchValue: target: address allow_failure: bool value: uint256 - call_data: Bytes[max_value(uint16)] + calldata: Bytes[1_024] # @dev Batch struct for ordinary (i.e. `nonpayable`) function calls # using this contract as destination address. struct BatchSelf: allow_failure: bool - call_data: Bytes[max_value(uint16)] + calldata: Bytes[1_024] # @dev Result struct for function call results. @@ -54,7 +58,7 @@ struct Result: return_data: Bytes[max_value(uint8)] -@external +@deploy @payable def __init__(): """ @@ -65,8 +69,8 @@ def __init__(): pass -@external -def multicall(data: DynArray[Batch, max_value(uint8)]) -> DynArray[Result, max_value(uint8)]: +@internal +def _multicall(data: DynArray[Batch, _DYNARRAY_BOUND]) -> DynArray[Result, _DYNARRAY_BOUND]: """ @dev Aggregates function calls, ensuring that each function returns successfully if required. @@ -78,24 +82,24 @@ def multicall(data: DynArray[Batch, max_value(uint8)]) -> DynArray[Result, max_v @param data The array of `Batch` structs. @return DynArray The array of `Result` structs. """ - results: DynArray[Result, max_value(uint8)] = [] + results: DynArray[Result, _DYNARRAY_BOUND] = [] return_data: Bytes[max_value(uint8)] = b"" success: bool = empty(bool) - for batch in data: + for batch: Batch in data: if (batch.allow_failure == False): - return_data = raw_call(batch.target, batch.call_data, max_outsize=255) + return_data = raw_call(batch.target, batch.calldata, max_outsize=255) success = True - results.append(Result({success: success, return_data: return_data})) + results.append(Result(success=success, return_data=return_data)) else: - success, return_data = \ - raw_call(batch.target, batch.call_data, max_outsize=255, revert_on_failure=False) - results.append(Result({success: success, return_data: return_data})) + success, return_data =\ + raw_call(batch.target, batch.calldata, max_outsize=255, revert_on_failure=False) + results.append(Result(success=success, return_data=return_data)) return results -@external +@internal @payable -def multicall_value(data: DynArray[BatchValue, max_value(uint8)]) -> DynArray[Result, max_value(uint8)]: +def _multicall_value(data: DynArray[BatchValue, _DYNARRAY_BOUND]) -> DynArray[Result, _DYNARRAY_BOUND]: """ @dev Aggregates function calls with a `msg.value`, ensuring that each function returns successfully @@ -109,31 +113,31 @@ def multicall_value(data: DynArray[BatchValue, max_value(uint8)]) -> DynArray[Re @return DynArray The array of `Result` structs. """ value_accumulator: uint256 = empty(uint256) - results: DynArray[Result, max_value(uint8)] = [] + results: DynArray[Result, _DYNARRAY_BOUND] = [] return_data: Bytes[max_value(uint8)] = b"" success: bool = empty(bool) - for batch in data: + for batch: BatchValue in data: msg_value: uint256 = batch.value # WARNING: If you expect to hold any funds in a contract that integrates # this function, you must ensure that the next line uses checked arithmetic! # Please read the contract-level security notice carefully. For further - # insights also, see the following Twitter thread: + # insights also, see the following X thread: # https://x.com/Guhu95/status/1736983530343981307. value_accumulator = unsafe_add(value_accumulator, msg_value) if (batch.allow_failure == False): - return_data = raw_call(batch.target, batch.call_data, max_outsize=255, value=msg_value) + return_data = raw_call(batch.target, batch.calldata, max_outsize=255, value=msg_value) success = True - results.append(Result({success: success, return_data: return_data})) + results.append(Result(success=success, return_data=return_data)) else: - success, return_data = \ - raw_call(batch.target, batch.call_data, max_outsize=255, value=msg_value, revert_on_failure=False) - results.append(Result({success: success, return_data: return_data})) - assert msg.value == value_accumulator, "Multicall: value mismatch" + success, return_data =\ + raw_call(batch.target, batch.calldata, max_outsize=255, value=msg_value, revert_on_failure=False) + results.append(Result(success=success, return_data=return_data)) + assert msg.value == value_accumulator, "multicall: value mismatch" return results -@external -def multicall_self(data: DynArray[BatchSelf, max_value(uint8)]) -> DynArray[Result, max_value(uint8)]: +@internal +def _multicall_self(data: DynArray[BatchSelf, _DYNARRAY_BOUND]) -> DynArray[Result, _DYNARRAY_BOUND]: """ @dev Aggregates function calls using `DELEGATECALL`, ensuring that each function returns successfully @@ -152,24 +156,24 @@ def multicall_self(data: DynArray[BatchSelf, max_value(uint8)]) -> DynArray[Resu @param data The array of `BatchSelf` structs. @return DynArray The array of `Result` structs. """ - results: DynArray[Result, max_value(uint8)] = [] + results: DynArray[Result, _DYNARRAY_BOUND] = [] return_data: Bytes[max_value(uint8)] = b"" success: bool = empty(bool) - for batch in data: + for batch: BatchSelf in data: if (batch.allow_failure == False): - return_data = raw_call(self, batch.call_data, max_outsize=255, is_delegate_call=True) + return_data = raw_call(self, batch.calldata, max_outsize=255, is_delegate_call=True) success = True - results.append(Result({success: success, return_data: return_data})) + results.append(Result(success=success, return_data=return_data)) else: - success, return_data = \ - raw_call(self, batch.call_data, max_outsize=255, is_delegate_call=True, revert_on_failure=False) - results.append(Result({success: success, return_data: return_data})) + success, return_data =\ + raw_call(self, batch.calldata, max_outsize=255, is_delegate_call=True, revert_on_failure=False) + results.append(Result(success=success, return_data=return_data)) return results -@external +@internal @view -def multistaticcall(data: DynArray[Batch, max_value(uint8)]) -> DynArray[Result, max_value(uint8)]: +def _multistaticcall(data: DynArray[Batch, _DYNARRAY_BOUND]) -> DynArray[Result, _DYNARRAY_BOUND]: """ @dev Aggregates static function calls, ensuring that each function returns successfully if required. @@ -179,16 +183,16 @@ def multistaticcall(data: DynArray[Batch, max_value(uint8)]) -> DynArray[Result, @param data The array of `Batch` structs. @return DynArray The array of `Result` structs. """ - results: DynArray[Result, max_value(uint8)] = [] + results: DynArray[Result, _DYNARRAY_BOUND] = [] return_data: Bytes[max_value(uint8)] = b"" success: bool = empty(bool) - for batch in data: + for batch: Batch in data: if (batch.allow_failure == False): - return_data = raw_call(batch.target, batch.call_data, max_outsize=255, is_static_call=True) + return_data = raw_call(batch.target, batch.calldata, max_outsize=255, is_static_call=True) success = True - results.append(Result({success: success, return_data: return_data})) + results.append(Result(success=success, return_data=return_data)) else: - success, return_data = \ - raw_call(batch.target, batch.call_data, max_outsize=255, is_static_call=True, revert_on_failure=False) - results.append(Result({success: success, return_data: return_data})) + success, return_data =\ + raw_call(batch.target, batch.calldata, max_outsize=255, is_static_call=True, revert_on_failure=False) + results.append(Result(success=success, return_data=return_data)) return results diff --git a/src/snekmate/utils/p256.vy b/src/snekmate/utils/p256.vy new file mode 100644 index 00000000..f6b98132 --- /dev/null +++ b/src/snekmate/utils/p256.vy @@ -0,0 +1,551 @@ +# pragma version ~=0.4.0rc6 +""" +@title Elliptic Curve Digital Signature Algorithm (ECDSA) Secp256r1-Based Functions +@custom:contract-name p256 +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +@notice These functions can be used to verify signatures based on the + non-Ethereum-native NIST P-256 elliptic curve (also known as + secp256r1; see https://neuromancer.sk/std/secg/secp256r1). For + more technical details, please refer to EIP-7212: + https://eips.ethereum.org/EIPS/eip-7212. + The implementation is inspired by dcposch's and nalinbhardwaj's + implementation here: + https://github.com/daimo-eth/p256-verifier/blob/master/src/P256Verifier.sol. +""" + + +# @notice All of the constant values defined subsequently are +# parameters for the elliptical curve secp256r1 (see the standard +# curve database: https://neuromancer.sk/std/secg/secp256r1). + + +# @dev Malleability threshold used as part of the ECDSA verification function. +_MALLEABILITY_THRESHOLD: constant(uint256) = 57_896_044_605_178_124_381_348_723_474_703_786_764_998_477_612_067_880_171_211_129_530_534_256_022_184 + + +# @dev The secp256r1 curve prime field modulus. +_P: constant(uint256) = 115_792_089_210_356_248_762_697_446_949_407_573_530_086_143_415_290_314_195_533_631_308_867_097_853_951 + + +# @dev Short Weierstrass first coefficient. +# @notice The assumption "_A == -3 (mod _P)" is used throughout +# the codebase. +_A: constant(uint256) = 115_792_089_210_356_248_762_697_446_949_407_573_530_086_143_415_290_314_195_533_631_308_867_097_853_948 +# @dev Short Weierstrass second coefficient. +_B: constant(uint256) = 41_058_363_725_152_142_129_326_129_780_047_268_409_114_441_015_993_725_554_835_256_314_039_467_401_291 + + +# @dev The base generator point for "(qx, qy)". +_GX: constant(uint256) = 48_439_561_293_906_451_759_052_585_252_797_914_202_762_949_526_041_747_995_844_080_717_082_404_635_286 +_GY: constant(uint256) = 36_134_250_956_749_795_798_585_127_919_587_881_956_611_106_672_985_015_071_877_198_253_568_414_405_109 + + +# @dev The secp256r1 curve order (number of points). +_N: constant(uint256) = 115_792_089_210_356_248_762_697_446_949_407_573_529_996_955_224_135_760_342_422_259_061_068_512_044_369 + + +# @dev The "-2 mod _P" constant is used to speed up inversion and +# doubling (avoid negation). +_MINUS_2MODP: constant(uint256) = 115_792_089_210_356_248_762_697_446_949_407_573_530_086_143_415_290_314_195_533_631_308_867_097_853_949 +# @dev The "-2 mod _N" constant is used to speed up inversion. +_MINUS_2MODN: constant(uint256) = 115_792_089_210_356_248_762_697_446_949_407_573_529_996_955_224_135_760_342_422_259_061_068_512_044_367 + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@internal +@view +def _verify_sig(hash: bytes32, r: uint256, s: uint256, qx: uint256, qy: uint256) -> bool: + """ + @dev Verifies the signature of a message digest `hash` + based on the secp256r1 signature parameters `r` and + `s`, and the public key coordinates `qx` and `qy`. + @param hash The 32-byte message digest that was signed. + @param r The secp256r1 32-byte signature parameter `r`. + @param s The secp256r1 32-byte signature parameter `s`. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @return bool The verification whether the signature is + authentic or not. + """ + assert s <= _MALLEABILITY_THRESHOLD, "p256: invalid signature `s` value" + + # Check if `r` and `s` are in the scalar field. + if ((r == empty(uint256)) or (r >= _N) or (s == empty(uint256)) or (s >= _N)): + return False + + if (not(self._ec_aff_is_valid_pubkey(qx, qy))): + return False + + s_inv: uint256 = self._n_mod_inv(s) + + # "(hash * s**(-1))" in scalar field. + scalar_u: uint256 = uint256_mulmod(convert(hash, uint256), s_inv, _N) + # "(r * s**(-1))" in scalar field. + scalar_v: uint256 = uint256_mulmod(r, s_inv, _N) + + r_x: uint256 = self._ec_zz_mulmuladd(qx, qy, scalar_u, scalar_v) + return r_x % _N == r + + +@internal +@pure +def _ec_aff_is_valid_pubkey(qx: uint256, qy: uint256) -> bool: + """ + @dev Checks if a point in affine coordinates is on + the curve. Rejects `0` point at infinity. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @return bool The verification whether the point is + on the curve or not. + """ + if ((qx >= _P) or (qy >= _P) or ((qx == empty(uint256)) and (qy == empty(uint256)))): + return False + + return self._ec_aff_satisfies_curve_eqn(qx, qy) + + +@internal +@pure +def _ec_aff_satisfies_curve_eqn(qx: uint256, qy: uint256) -> bool: + """ + @dev Checks if a point in affine coordinates satisfies + the curve equation. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @return bool The verification whether the point satisfies + the curve equation or not. + """ + # "qy**2". + lhs: uint256 = uint256_mulmod(qy, qy, _P) + # "qx**3 + _A*qx + _B". + rhs: uint256 = uint256_addmod(uint256_addmod(uint256_mulmod(uint256_mulmod(qx, qx, _P), qx, _P), uint256_mulmod(_A, qx, _P), _P), _B, _P) + return lhs == rhs + + +@internal +@view +def _ec_zz_mulmuladd(qx: uint256, qy: uint256, scalar_u: uint256, scalar_v: uint256) -> uint256: + """ + @dev Computes "uG + vQ" using Strauss-Shamir's trick + (G = basepoint, Q = public key). Strauss-Shamir + is described well here: + https://stackoverflow.com/a/50994362. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @param scalar_u The 32-byte field scalar `u`. + @param scalar_v The 32-byte field scalar `v`. + @return uint256 The 32-byte calculation result. + """ + zz1: uint256 = 1 + zzz1: uint256 = 1 + qx1: uint256 = empty(uint256) + qy1: uint256 = empty(uint256) + hx: uint256 = empty(uint256) + hy: uint256 = empty(uint256) + + if ((scalar_u == empty(uint256)) and (scalar_v == empty(uint256))): + return empty(uint256) + + # "H = G + Q". + (hx, hy) = self._ec_aff_add(_GX, _GY, qx, qy) + + index: int256 = 255 + bitpair: uint256 = empty(uint256) + + # Find the first bit index that is active in either + # `scalar_u` or `scalar_v`. + for _: uint256 in range(255): + bitpair = self._compute_bitpair(convert(index, uint256), scalar_u, scalar_v) + # The following line cannot negatively overflow + # because we have limited the for-loop by the + # constant value `255`. The theoretically maximum + # achievable value is therefore `-1`. + index = unsafe_sub(index, 1) + if (bitpair != empty(uint256)): + break + + if (bitpair == 1): + qx1 = _GX + qy1 = _GY + elif (bitpair == 2): + qx1 = qx + qy1 = qy + elif (bitpair == 3): + qx1 = hx + qy1 = hy + + qx2: uint256 = empty(uint256) + qy2: uint256 = empty(uint256) + + for _: uint256 in range(255): + if (index < empty(int256)): + break + + (qx1, qy1, zz1, zzz1) = self._ec_zz_double_zz(qx1, qy1, zz1, zzz1) + bitpair = self._compute_bitpair(convert(index, uint256), scalar_u, scalar_v) + # The following line cannot negatively overflow + # because we have limited the for-loop by the + # constant value `255`. The theoretically maximum + # achievable value is therefore `-1`. + index = unsafe_sub(index, 1) + + if (bitpair == empty(uint256)): + continue + elif (bitpair == 1): + qx2 = _GX + qy2 = _GY + elif (bitpair == 2): + qx2 = qx + qy2 = qy + else: + qx2 = hx + qy2 = hy + + (qx1, qy1, zz1, zzz1) = self._ec_zz_dadd_affine(qx1, qy1, zz1, zzz1, qx2, qy2) + + # If `zz1 = 0` then `zz1_inv = 0`. + zz1_inv: uint256 = self._p_mod_inv(zz1) + # "qx1/zz1". + return uint256_mulmod(qx1, zz1_inv, _P) + + +@internal +@pure +def _compute_bitpair(index: uint256, scalar_u: uint256, scalar_v: uint256) -> uint256: + """ + @dev Computes the bits at `index` of `scalar_u` and + `scalar_v` and returns 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`. + @param index The 32-byte index. + @param scalar_u The 32-byte field scalar `u`. + @param scalar_v The 32-byte field scalar `v`. + @return uint256 The 32-byte calculation result. + """ + return (((scalar_v >> index) & 1) << 1) | ((scalar_u >> index) & 1) + + +@internal +@view +def _ec_aff_add(qx1: uint256, qy1: uint256, qx2: uint256, qy2: uint256) -> (uint256, uint256): + """ + @dev Adds two elliptic curve points in affine coordinates. + Assumes that the points are on the elliptic curve. + @param qx1 The first 32-byte public key coordinate `qx1`. + @param qy1 The first 32-byte public key coordinate `qy1`. + @param qx2 The second 32-byte public key coordinate `qx2`. + @param qy2 The second 32-byte public key coordinate `qy2`. + @return uint256 The computed 32-byte public key coordinate `qx`. + @return uint256 The computed 32-byte public key coordinate `qy`. + """ + zz1: uint256 = empty(uint256) + zzz1: uint256 = empty(uint256) + + if (self._ec_aff_is_inf(qx1, qy1)): + return (qx2, qy2) + + if (self._ec_aff_is_inf(qx2, qy2)): + return (qx1, qy1) + + (qx1, qy1, zz1, zzz1) = self._ec_zz_dadd_affine(qx1, qy1, 1, 1, qx2, qy2) + return self._ec_zz_set_aff(qx1, qy1, zz1, zzz1) + + +@internal +@pure +def _ec_aff_is_inf(qx: uint256, qy: uint256) -> bool: + """ + @dev Checks if a point is the infinity point in affine + representation. Assumes that the point is on the + elliptic curve or is the point at infinity. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @return bool The verification whether a point is + the infinity point or not. + """ + return ((qx == empty(uint256)) and (qy == empty(uint256))) + + +@internal +@pure +def _ec_zz_is_inf(zz: uint256, zzz: uint256) -> bool: + """ + @dev Checks if a point is the infinity point in ZZ + representation. Assumes point is on the + elliptic curve or is the point at infinity. + @param zz The 32-byte public key coordinate `qx` in ZZ + representation. + @param zzz The 32-byte public key coordinate `qy` in ZZ + representation. + @return bool The verification whether a point is + the infinity point or not. + """ + return ((zz == empty(uint256)) and (zzz == empty(uint256))) + + +@internal +@view +def _ec_zz_dadd_affine(qx1: uint256, qy1: uint256, zz1: uint256, zzz1: uint256, qx2: uint256, qy2: uint256) -> (uint256, uint256, uint256, uint256): + """ + @dev Adds a ZZ point to an affine point and returns as + ZZ representation. Uses "madd-2008-s" and "mdbl-2008-s" + internally: + https://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz-3.html#addition-madd-2008-s. + It matches closely: + https://github.com/supranational/blst/blob/704c7f6d5f99ebb6bda84f635122e449ee51aa48/src/ec_ops.h#L710. + Handles points at infinity gracefully. + @param qx1 The first 32-byte public key coordinate `qx1`. + @param qy1 The first 32-byte public key coordinate `qy1`. + @param zz1 The 32-byte public key coordinate `qx1` in ZZ + representation. + @param zzz1 The 32-byte public key coordinate `qy1` in ZZ + representation. + @param qx2 The second 32-byte public key coordinate `qx2`. + @param qy2 The second 32-byte public key coordinate `qy2`. + @return uint256 The computed 32-byte public key coordinate `qx`. + @return uint256 The computed 32-byte public key coordinate `qy`. + @return uint256 The computed 32-byte public key coordinate `qx` + in ZZ representation. + @return uint256 The computed 32-byte public key coordinate `qy` + in ZZ representation. + """ + qx3: uint256 = empty(uint256) + qy3: uint256 = empty(uint256) + zz3: uint256 = empty(uint256) + zzz3: uint256 = empty(uint256) + + # `(qx2, qy2)` is point at infinity. + if (self._ec_aff_is_inf(qx2, qy2)): + if (self._ec_zz_is_inf(zz1, zzz1)): + return self._ec_zz_point_at_inf() + return (qx1, qy1, zz1, zzz1) + # `(qx1, qy1)` is point at infinity. + elif (self._ec_zz_is_inf(zz1, zzz1)): + return (qx2, qy2, 1, 1) + + # "r = s2 - qy1 = qy2*zzz1 - qy1". + comp_r: uint256 = uint256_addmod(uint256_mulmod(qy2, zzz1, _P), unsafe_sub(_P, qy1), _P) + # "p = u2 - qx1 = qx2*zz1 - qx1". + comp_p: uint256 = uint256_addmod(uint256_mulmod(qx2, zz1, _P), unsafe_sub(_P, qx1), _P) + + # "qx1 != qx2". + if (comp_p != empty(uint256)): + # "pp = p**2". + comp_pp: uint256 = uint256_mulmod(comp_p, comp_p, _P) + # "ppp = p*pp". + comp_ppp: uint256 = uint256_mulmod(comp_pp, comp_p, _P) + # "zz3 = zz1*pp". + zz3 = uint256_mulmod(zz1, comp_pp, _P) + # "zzz3 = zzz1*ppp". + zzz3 = uint256_mulmod(zzz1, comp_ppp, _P) + # "q = qx1*pp". + comp_q: uint256 = uint256_mulmod(qx1, comp_pp, _P) + # "r**2 - ppp - 2*q". + qx3 = uint256_addmod(uint256_addmod(uint256_mulmod(comp_r, comp_r, _P), unsafe_sub(_P, comp_ppp), _P),\ + uint256_mulmod(_MINUS_2MODP, comp_q, _P), _P) + # "qy3 = r*(q-qx3) - qy1*ppp". + return (qx3, uint256_addmod(uint256_mulmod(uint256_addmod(comp_q, unsafe_sub(_P, qx3), _P), comp_r, _P),\ + uint256_mulmod(unsafe_sub(_P, qy1), comp_ppp, _P), _P), zz3, zzz3) + # "qx1 == qx2 and qy1 == qy2". + elif (comp_r == empty(uint256)): + return self._ec_zz_double_affine(qx2, qy2) + + # "qx1 == qx2 and qy1 == -qy2". + return self._ec_zz_point_at_inf() + + +@internal +@pure +def _ec_zz_double_zz(qx: uint256, qy: uint256, zz: uint256, zzz: uint256) -> (uint256, uint256, uint256, uint256): + """ + @dev Doubles a ZZ point. Uses: http://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1. + Handles points at infinity gracefully. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @param zz The 32-byte public key coordinate `qx` in ZZ + representation. + @param zzz The 32-byte public key coordinate `qy` in ZZ + representation. + @return uint256 The computed 32-byte public key coordinate `qx`. + @return uint256 The computed 32-byte public key coordinate `qy`. + @return uint256 The computed 32-byte public key coordinate `qx` + in ZZ representation. + @return uint256 The computed 32-byte public key coordinate `qy` + in ZZ representation. + """ + if (self._ec_zz_is_inf(zz, zzz)): + return self._ec_zz_point_at_inf() + + # "u = 2*qy". + comp_u: uint256 = uint256_mulmod(2, qy, _P) + # "v = u**2". + comp_v: uint256 = uint256_mulmod(comp_u, comp_u, _P) + # "w = u*v". + comp_w: uint256 = uint256_mulmod(comp_u, comp_v, _P) + # "s = qx*v". + comp_s: uint256 = uint256_mulmod(qx, comp_v, _P) + # "m = 3*(qx)**2 + _A*(zz)**2". + comp_m: uint256 = uint256_addmod(uint256_mulmod(3, uint256_mulmod(qx, qx, _P), _P), uint256_mulmod(_A,\ + uint256_mulmod(zz, zz, _P), _P), _P) + + # "m**2 + (-2)*s". + qx3: uint256 = uint256_addmod(uint256_mulmod(comp_m, comp_m, _P), uint256_mulmod(_MINUS_2MODP, comp_s, _P), _P) + # "qy3 = m*(s+(-qx3)) + (-w)*qy, zz3 = v*zz, zzz3 = w*zzz". + return (qx3, uint256_addmod(uint256_mulmod(comp_m, uint256_addmod(comp_s, unsafe_sub(_P, qx3), _P), _P),\ + uint256_mulmod(unsafe_sub(_P, comp_w), qy, _P), _P), uint256_mulmod(comp_v, zz, _P), uint256_mulmod(comp_w, zzz, _P)) + + +@internal +@view +def _ec_zz_double_affine(qx: uint256, qy: uint256) -> (uint256, uint256, uint256, uint256): + """ + @dev Doubles an affine point and returns as a ZZ point. + Uses: http://hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-mdbl-2008-s-1. + Handles point at infinity gracefully. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @return uint256 The computed 32-byte public key coordinate `qx`. + @return uint256 The computed 32-byte public key coordinate `qy`. + @return uint256 The computed 32-byte public key coordinate `qx` + in ZZ representation. + @return uint256 The computed 32-byte public key coordinate `qy` + in ZZ representation. + """ + if (self._ec_aff_is_inf(qx, qy)): + return self._ec_zz_point_at_inf() + + # "u = 2*qy". + comp_u: uint256 = uint256_mulmod(2, qy, _P) + # "v = u**2 = zz3". + zz3: uint256 = uint256_mulmod(comp_u, comp_u, _P) + # "w = u*v = zzz3". + zzz3: uint256 = uint256_mulmod(comp_u, zz3, _P) + # "s = qx*v". + comp_s: uint256 = uint256_mulmod(qx, zz3, _P) + # "m = 3*(qx)**2 + _A". + comp_m: uint256 = uint256_addmod(uint256_mulmod(3, uint256_mulmod(qx, qx, _P), _P), _A, _P) + + # "m**2 + (-2)*s". + qx3: uint256 = uint256_addmod(uint256_mulmod(comp_m, comp_m, _P), uint256_mulmod(_MINUS_2MODP, comp_s, _P), _P) + # "qy3 = m*(s+(-qx3)) + (-w)*qy". + return (qx3, uint256_addmod(uint256_mulmod(comp_m, uint256_addmod(comp_s, unsafe_sub(_P, qx3), _P), _P),\ + uint256_mulmod(unsafe_sub(_P, zzz3), qy, _P), _P), zz3, zzz3) + + +@internal +@view +def _ec_zz_set_aff(qx: uint256, qy: uint256, zz: uint256, zzz: uint256) -> (uint256, uint256): + """ + @dev Converts from ZZ representation to affine representation. + 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. + @param qx The 32-byte public key coordinate `qx`. + @param qy The 32-byte public key coordinate `qy`. + @param zz The 32-byte public key coordinate `qx` in ZZ + representation. + @param zzz The 32-byte public key coordinate `qy` in ZZ + representation. + @return uint256 The computed 32-byte public key coordinate `qx`. + @return uint256 The computed 32-byte public key coordinate `qy`. + """ + qx1: uint256 = empty(uint256) + qy1: uint256 = empty(uint256) + if (self._ec_zz_is_inf(zz, zzz)): + return self._ec_affine_point_at_inf() + + # "1/zzz". + zzz_inv: uint256 = self._p_mod_inv(zzz) + # "1/z". + z_inv: uint256 = uint256_mulmod(zz, zzz_inv, _P) + # "1/zz". + zz_inv: uint256 = uint256_mulmod(z_inv, z_inv, _P) + + # "qx1 = qx/zz, qy1 = qy/zzz." + return (uint256_mulmod(qx, zz_inv, _P), uint256_mulmod(qy, zzz_inv, _P)) + + +@internal +@pure +def _ec_zz_point_at_inf() -> (uint256, uint256, uint256, uint256): + """ + @dev Computes the point at infinity in ZZ representation. + @return uint256 The computed 32-byte public key coordinate `qx`. + @return uint256 The computed 32-byte public key coordinate `qy`. + @return uint256 zz The computed 32-byte public key coordinate `qx` + in ZZ representation. + @return uint256 zzz The computed 32-byte public key coordinate `qy` + in ZZ representation. + """ + return (empty(uint256), empty(uint256), empty(uint256), empty(uint256)) + + +@internal +@pure +def _ec_affine_point_at_inf() -> (uint256, uint256): + """ + @dev Computes the point at infinity in affine representation. + @return uint256 The computed 32-byte public key coordinate `qx`. + @return uint256 The computed 32-byte public key coordinate `qy`. + """ + return (empty(uint256), empty(uint256)) + + +@internal +@view +def _n_mod_inv(u: uint256) -> uint256: + """ + @dev Computes "u**(-1) mod _N". + @param u The 32-byte input parameter. + @return uint256 The 32-byte calculation result. + """ + return self._mod_inv(u, _N, _MINUS_2MODN) + + +@internal +@view +def _p_mod_inv(u: uint256) -> uint256: + """ + @dev Computes "u"**(-1) mod _P". + @param u The 32-byte input parameter. + @return uint256 The 32-byte calculation result. + """ + return self._mod_inv(u, _P, _MINUS_2MODP) + + +@internal +@view +def _mod_inv(u: uint256, f: uint256, minus_2modf: uint256) -> uint256: + """ + @dev Computes "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 the `modexp` precompile. Assumes "f != 0". If `u` is `0`, + then "u**(-1) mod f" is undefined mathematically, but this function + returns `0`. + @param u The first 32-byte input parameter. + @param f The second 32-byte input parameter. + @param minus_2modf The 32-bytes "-2 mod f" constant. + @return uint256 The 32-byte calculation result. + """ + c: uint256 = 32 + modexp: address = 0x0000000000000000000000000000000000000005 + return_data: Bytes[32] = b"" + return_data = raw_call(modexp, _abi_encode(c, c, c, u, minus_2modf, f), max_outsize=32, is_static_call=True) + # Since the `modexp` precompile cannot revert, we do + # not assert a successful return. + return _abi_decode(return_data, (uint256)) diff --git a/src/snekmate/utils/signature_checker.vy b/src/snekmate/utils/signature_checker.vy new file mode 100644 index 00000000..55aa4f78 --- /dev/null +++ b/src/snekmate/utils/signature_checker.vy @@ -0,0 +1,113 @@ +# pragma version ~=0.4.0rc6 +""" +@title ECDSA and EIP-1271 Signature Verification Functions +@custom:contract-name signature_checker +@license GNU Affero General Public License v3.0 only +@author pcaversaccio +@notice Signature verification helper functions that can be used + instead of {ecdsa-_recover_sig} to seamlessly support both + ECDSA secp256k1-based (see https://en.bitcoin.it/wiki/Secp256k1) + signatures from externally-owned accounts (EOAs) as well as + EIP-1271 (https://eips.ethereum.org/EIPS/eip-1271) signatures + from smart contract wallets like Argent and Safe. For strict + EIP-1271 verification, i.e. only valid EIP-1271 signatures are + verified, the function `_is_valid_ERC1271_signature_now` can + be called. The implementation is inspired by OpenZeppelin's + implementation here: + https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol. +@custom:security Signatures must not be used as unique identifiers since the + `ecrecover` EVM precompile allows for malleable (non-unique) + signatures (see EIP-2: https://eips.ethereum.org/EIPS/eip-2) + or signatures can be malleablised using EIP-2098: + https://eips.ethereum.org/EIPS/eip-2098. +""" + + +# @dev We import the `ecdsa` module. +# @notice Please note that the `ecdsa` module +# is stateless and therefore does not require +# the `uses` keyword for usage. +from . import ecdsa + + +# @dev The 4-byte function selector of `isValidSignature(bytes32,bytes)`. +# @notice If you declare a variable as `public`, +# Vyper automatically generates an `external` +# getter function for the variable. +IERC1271_ISVALIDSIGNATURE_SELECTOR: public(constant(bytes4)) = 0x1626BA7E + + +@deploy +@payable +def __init__(): + """ + @dev To omit the opcodes for checking the `msg.value` + in the creation-time EVM bytecode, the constructor + is declared as `payable`. + """ + pass + + +@internal +@view +def _is_valid_signature_now(signer: address, hash: bytes32, signature: Bytes[65]) -> bool: + """ + @dev Checks if a signature `signature` is valid + for a given `signer` and message digest `hash`. + If the signer is a smart contract, the signature + is validated against that smart contract using + EIP-1271, otherwise it's validated using {ecdsa-_recover_sig}. + @notice Unlike ECDSA signatures, contract signatures + are revocable and the result of this function + can therefore change over time. It could return + `True` in block N and `False` in block N+1 (or the opposite). + @param signer The 20-byte signer address. + @param hash The 32-byte message digest that was signed. + @param signature The maximum 65-byte signature of `hash`. + @return bool The verification whether `signature` is valid + for the provided data. + @custom:security Since we avoid validating ECDSA signatures + when code is deployed at the signer's address, + it is safe if EIP-7377 (https://eips.ethereum.org/EIPS/eip-7377) + should be deployed one day. + """ + # First check: ECDSA case. + if (not(signer.is_contract)): + return ecdsa._recover_sig(hash, signature) == signer + + # Second check: EIP-1271 case. + return self._is_valid_ERC1271_signature_now(signer, hash, signature) + + +@internal +@view +def _is_valid_ERC1271_signature_now(signer: address, hash: bytes32, signature: Bytes[65]) -> bool: + """ + @dev Checks if a signature `signature` is valid + for a given `signer` and message digest `hash`. + The signature is validated using EIP-1271. + @notice Unlike ECDSA signatures, contract signatures + are revocable and the result of this function + can therefore change over time. It could return + `True` in block N and `False` in block N+1 (or the opposite). + @param signer The 20-byte signer address. + @param hash The 32-byte message digest that was signed. + @param signature The maximum 65-byte signature of `hash`. + @return bool The verification whether `signature` is valid + for the provided data. + """ + success: bool = empty(bool) + return_data: Bytes[32] = b"" + # The following low-level call does not revert, but instead + # returns `False` if the callable contract does not implement + # the `isValidSignature` function. Since we perform a length + # check of 32 bytes for the return data in the return expression + # at the end, we also return `False` for EOA wallets instead + # of reverting (remember that the EVM always considers a call + # to an EOA as successful with return data `0x`). Furthermore, + # it is important to note that an external call via `raw_call` + # does not perform an external code size check on the target + # address. + success, return_data =\ + raw_call(signer, _abi_encode(hash, signature, method_id=IERC1271_ISVALIDSIGNATURE_SELECTOR), max_outsize=32, is_static_call=True, revert_on_failure=False) + return ((success) and (len(return_data) == 32) and (convert(return_data, bytes32) == convert(IERC1271_ISVALIDSIGNATURE_SELECTOR, bytes32))) diff --git a/test/auth/AccessControl.t.sol b/test/auth/AccessControl.t.sol index 30a391af..1f593970 100644 --- a/test/auth/AccessControl.t.sol +++ b/test/auth/AccessControl.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -11,8 +11,8 @@ import {IAccessControlExtended} from "./interfaces/IAccessControlExtended.sol"; contract AccessControlTest is Test { bytes32 private constant DEFAULT_ADMIN_ROLE = bytes32(0); - bytes32 private constant ADDITIONAL_ROLE_1 = keccak256("ADDITIONAL_ROLE_1"); - bytes32 private constant ADDITIONAL_ROLE_2 = keccak256("ADDITIONAL_ROLE_2"); + bytes32 private constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 private constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); VyperDeployer private vyperDeployer = new VyperDeployer(); @@ -23,70 +23,60 @@ contract AccessControlTest is Test { function setUp() public { accessControl = IAccessControlExtended( - vyperDeployer.deployContract("src/snekmate/auth/", "AccessControl") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "access_control_mock" + ) ); } function testInitialSetup() public { assertEq(accessControl.DEFAULT_ADMIN_ROLE(), DEFAULT_ADMIN_ROLE); - assertEq(accessControl.ADDITIONAL_ROLE_1(), ADDITIONAL_ROLE_1); - assertEq(accessControl.ADDITIONAL_ROLE_2(), ADDITIONAL_ROLE_2); + assertEq(accessControl.MINTER_ROLE(), MINTER_ROLE); + assertEq(accessControl.PAUSER_ROLE(), PAUSER_ROLE); assertTrue(accessControl.hasRole(DEFAULT_ADMIN_ROLE, deployer)); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, deployer)); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_2, deployer)); + assertTrue(accessControl.hasRole(MINTER_ROLE, deployer)); + assertTrue(accessControl.hasRole(PAUSER_ROLE, deployer)); assertEq( accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE), DEFAULT_ADMIN_ROLE ); - assertEq( - accessControl.getRoleAdmin(ADDITIONAL_ROLE_1), - DEFAULT_ADMIN_ROLE - ); - assertEq( - accessControl.getRoleAdmin(ADDITIONAL_ROLE_2), - DEFAULT_ADMIN_ROLE - ); + assertEq(accessControl.getRoleAdmin(MINTER_ROLE), DEFAULT_ADMIN_ROLE); + assertEq(accessControl.getRoleAdmin(PAUSER_ROLE), DEFAULT_ADMIN_ROLE); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleGranted(DEFAULT_ADMIN_ROLE, deployer, deployer); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, deployer, deployer); + emit IAccessControl.RoleGranted(MINTER_ROLE, deployer, deployer); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_2, deployer, deployer); + emit IAccessControl.RoleGranted(PAUSER_ROLE, deployer, deployer); accessControlInitialEvent = IAccessControlExtended( - vyperDeployer.deployContract("src/snekmate/auth/", "AccessControl") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "access_control_mock" + ) ); assertEq( accessControlInitialEvent.DEFAULT_ADMIN_ROLE(), DEFAULT_ADMIN_ROLE ); - assertEq( - accessControlInitialEvent.ADDITIONAL_ROLE_1(), - ADDITIONAL_ROLE_1 - ); - assertEq( - accessControlInitialEvent.ADDITIONAL_ROLE_2(), - ADDITIONAL_ROLE_2 - ); + assertEq(accessControlInitialEvent.MINTER_ROLE(), MINTER_ROLE); + assertEq(accessControlInitialEvent.PAUSER_ROLE(), PAUSER_ROLE); assertTrue( accessControlInitialEvent.hasRole(DEFAULT_ADMIN_ROLE, deployer) ); - assertTrue( - accessControlInitialEvent.hasRole(ADDITIONAL_ROLE_1, deployer) - ); - assertTrue( - accessControlInitialEvent.hasRole(ADDITIONAL_ROLE_2, deployer) - ); + assertTrue(accessControlInitialEvent.hasRole(MINTER_ROLE, deployer)); + assertTrue(accessControlInitialEvent.hasRole(PAUSER_ROLE, deployer)); assertEq( accessControlInitialEvent.getRoleAdmin(DEFAULT_ADMIN_ROLE), DEFAULT_ADMIN_ROLE ); assertEq( - accessControlInitialEvent.getRoleAdmin(ADDITIONAL_ROLE_1), + accessControlInitialEvent.getRoleAdmin(MINTER_ROLE), DEFAULT_ADMIN_ROLE ); assertEq( - accessControlInitialEvent.getRoleAdmin(ADDITIONAL_ROLE_2), + accessControlInitialEvent.getRoleAdmin(PAUSER_ROLE), DEFAULT_ADMIN_ROLE ); } @@ -126,9 +116,9 @@ contract AccessControlTest is Test { address account = makeAddr("account"); vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -148,40 +138,40 @@ contract AccessControlTest is Test { address account = makeAddr("account"); vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } function testGrantRoleNonAdmin() public { - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.grantRole(ADDITIONAL_ROLE_1, makeAddr("account")); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.grantRole(MINTER_ROLE, makeAddr("account")); } function testRevokeRoleSuccess() public { address admin = deployer; address account = makeAddr("account"); vm.startPrank(admin); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, admin); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, admin); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -190,20 +180,20 @@ contract AccessControlTest is Test { address account = makeAddr("account"); vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, admin); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, admin); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -216,14 +206,14 @@ contract AccessControlTest is Test { accessControl.revokeRole(DEFAULT_ADMIN_ROLE, admin); assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin)); - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.revokeRole(ADDITIONAL_ROLE_1, admin); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.revokeRole(MINTER_ROLE, admin); vm.stopPrank(); } function testRevokeRoleNonAdmin() public { - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.revokeRole(ADDITIONAL_ROLE_1, makeAddr("account")); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.revokeRole(MINTER_ROLE, makeAddr("account")); } function testRenounceRoleSuccess() public { @@ -231,9 +221,9 @@ contract AccessControlTest is Test { address account = makeAddr("account"); vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); vm.startPrank(account); @@ -242,9 +232,9 @@ contract AccessControlTest is Test { assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, account); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, account); + accessControl.renounceRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -253,9 +243,9 @@ contract AccessControlTest is Test { address account = makeAddr("account"); vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); vm.startPrank(account); @@ -264,15 +254,15 @@ contract AccessControlTest is Test { assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, account); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, account); + accessControl.renounceRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.renounceRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.renounceRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -292,9 +282,9 @@ contract AccessControlTest is Test { function testRenounceRoleNonMsgSender() public { vm.expectRevert( - bytes("AccessControl: can only renounce roles for itself") + bytes("access_control: can only renounce roles for itself") ); - accessControl.renounceRole(ADDITIONAL_ROLE_1, makeAddr("account")); + accessControl.renounceRole(MINTER_ROLE, makeAddr("account")); } function testSetRoleAdminSuccess() public { @@ -305,11 +295,11 @@ contract AccessControlTest is Test { vm.startPrank(admin); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleAdminChanged( - ADDITIONAL_ROLE_1, + MINTER_ROLE, DEFAULT_ADMIN_ROLE, otherAdminRole ); - accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole); + accessControl.set_role_admin(MINTER_ROLE, otherAdminRole); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleGranted(otherAdminRole, otherAdmin, admin); @@ -318,16 +308,16 @@ contract AccessControlTest is Test { vm.stopPrank(); vm.startPrank(otherAdmin); - assertEq(accessControl.getRoleAdmin(ADDITIONAL_ROLE_1), otherAdminRole); + assertEq(accessControl.getRoleAdmin(MINTER_ROLE), otherAdminRole); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, otherAdmin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, otherAdmin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, otherAdmin); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, otherAdmin); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -339,19 +329,19 @@ contract AccessControlTest is Test { vm.startPrank(admin); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleAdminChanged( - ADDITIONAL_ROLE_1, + MINTER_ROLE, DEFAULT_ADMIN_ROLE, otherAdminRole ); - accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole); + accessControl.set_role_admin(MINTER_ROLE, otherAdminRole); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleGranted(otherAdminRole, otherAdmin, admin); accessControl.grantRole(otherAdminRole, otherAdmin); assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin)); - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.grantRole(MINTER_ROLE, account); vm.stopPrank(); } @@ -361,23 +351,23 @@ contract AccessControlTest is Test { address account = makeAddr("account"); bytes32 otherAdminRole = keccak256("OTHER_ADMIN_ROLE"); vm.startPrank(admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); + accessControl.grantRole(MINTER_ROLE, account); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleAdminChanged( - ADDITIONAL_ROLE_1, + MINTER_ROLE, DEFAULT_ADMIN_ROLE, otherAdminRole ); - accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole); + accessControl.set_role_admin(MINTER_ROLE, otherAdminRole); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleGranted(otherAdminRole, otherAdmin, admin); accessControl.grantRole(otherAdminRole, otherAdmin); assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin)); - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.revokeRole(MINTER_ROLE, account); vm.stopPrank(); } @@ -386,9 +376,9 @@ contract AccessControlTest is Test { address admin = deployer; vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -408,15 +398,15 @@ contract AccessControlTest is Test { address admin = deployer; vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -426,27 +416,27 @@ contract AccessControlTest is Test { ) public { vm.assume(nonAdmin != deployer); vm.prank(nonAdmin); - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.grantRole(MINTER_ROLE, account); } function testFuzzRevokeRoleSuccess(address account) public { vm.assume(account != deployer); address admin = deployer; vm.startPrank(admin); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, admin); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, admin); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -455,20 +445,20 @@ contract AccessControlTest is Test { address admin = deployer; vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, admin); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, admin); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -478,8 +468,8 @@ contract AccessControlTest is Test { ) public { vm.assume(nonAdmin != deployer); vm.prank(nonAdmin); - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.revokeRole(MINTER_ROLE, account); } function testFuzzRenounceRoleSuccess(address account) public { @@ -487,9 +477,9 @@ contract AccessControlTest is Test { address admin = deployer; vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); vm.startPrank(account); @@ -498,9 +488,9 @@ contract AccessControlTest is Test { assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, account); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, account); + accessControl.renounceRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -509,9 +499,9 @@ contract AccessControlTest is Test { address admin = deployer; vm.startPrank(admin); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, admin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); vm.startPrank(account); @@ -520,24 +510,24 @@ contract AccessControlTest is Test { assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, account); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, account); + accessControl.renounceRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.renounceRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + accessControl.renounceRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } function testFuzzRenounceRoleNonMsgSender(address account) public { vm.assume(address(this) != account); vm.expectRevert( - bytes("AccessControl: can only renounce roles for itself") + bytes("access_control: can only renounce roles for itself") ); - accessControl.renounceRole(ADDITIONAL_ROLE_1, account); + accessControl.renounceRole(MINTER_ROLE, account); } function testFuzzSetRoleAdminSuccess( @@ -550,11 +540,11 @@ contract AccessControlTest is Test { vm.startPrank(admin); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleAdminChanged( - ADDITIONAL_ROLE_1, + MINTER_ROLE, DEFAULT_ADMIN_ROLE, otherAdminRole ); - accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole); + accessControl.set_role_admin(MINTER_ROLE, otherAdminRole); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleGranted(otherAdminRole, otherAdmin, admin); @@ -563,16 +553,16 @@ contract AccessControlTest is Test { vm.stopPrank(); vm.startPrank(otherAdmin); - assertEq(accessControl.getRoleAdmin(ADDITIONAL_ROLE_1), otherAdminRole); + assertEq(accessControl.getRoleAdmin(MINTER_ROLE), otherAdminRole); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_1, account, otherAdmin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); - assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleGranted(MINTER_ROLE, account, otherAdmin); + accessControl.grantRole(MINTER_ROLE, account); + assertTrue(accessControl.hasRole(MINTER_ROLE, account)); vm.expectEmit(true, true, true, false); - emit IAccessControl.RoleRevoked(ADDITIONAL_ROLE_1, account, otherAdmin); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); - assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account)); + emit IAccessControl.RoleRevoked(MINTER_ROLE, account, otherAdmin); + accessControl.revokeRole(MINTER_ROLE, account); + assertTrue(!accessControl.hasRole(MINTER_ROLE, account)); vm.stopPrank(); } @@ -586,19 +576,19 @@ contract AccessControlTest is Test { vm.startPrank(admin); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleAdminChanged( - ADDITIONAL_ROLE_1, + MINTER_ROLE, DEFAULT_ADMIN_ROLE, otherAdminRole ); - accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole); + accessControl.set_role_admin(MINTER_ROLE, otherAdminRole); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleGranted(otherAdminRole, otherAdmin, admin); accessControl.grantRole(otherAdminRole, otherAdmin); assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin)); - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.grantRole(MINTER_ROLE, account); vm.stopPrank(); } @@ -610,31 +600,31 @@ contract AccessControlTest is Test { address admin = deployer; bytes32 otherAdminRole = keccak256("OTHER_ADMIN_ROLE"); vm.startPrank(admin); - accessControl.grantRole(ADDITIONAL_ROLE_1, account); + accessControl.grantRole(MINTER_ROLE, account); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleAdminChanged( - ADDITIONAL_ROLE_1, + MINTER_ROLE, DEFAULT_ADMIN_ROLE, otherAdminRole ); - accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole); + accessControl.set_role_admin(MINTER_ROLE, otherAdminRole); vm.expectEmit(true, true, true, false); emit IAccessControl.RoleGranted(otherAdminRole, otherAdmin, admin); accessControl.grantRole(otherAdminRole, otherAdmin); assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin)); - vm.expectRevert(bytes("AccessControl: account is missing role")); - accessControl.revokeRole(ADDITIONAL_ROLE_1, account); + vm.expectRevert(bytes("access_control: account is missing role")); + accessControl.revokeRole(MINTER_ROLE, account); vm.stopPrank(); } } contract AccessControlInvariants is Test { bytes32 private constant DEFAULT_ADMIN_ROLE = bytes32(0); - bytes32 private constant ADDITIONAL_ROLE_1 = keccak256("ADDITIONAL_ROLE_1"); - bytes32 private constant ADDITIONAL_ROLE_2 = keccak256("ADDITIONAL_ROLE_2"); + bytes32 private constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 private constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); VyperDeployer private vyperDeployer = new VyperDeployer(); @@ -645,45 +635,48 @@ contract AccessControlInvariants is Test { function setUp() public { accessControl = IAccessControlExtended( - vyperDeployer.deployContract("src/snekmate/auth/", "AccessControl") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "access_control_mock" + ) ); accessControlHandler = new AccessControlHandler( accessControl, deployer, DEFAULT_ADMIN_ROLE, - ADDITIONAL_ROLE_1, - ADDITIONAL_ROLE_2 + MINTER_ROLE, + PAUSER_ROLE ); targetContract(address(accessControlHandler)); } - function invariantHasRole() public view { + function statefulFuzzHasRole() public view { assertEq( accessControl.hasRole(DEFAULT_ADMIN_ROLE, deployer), accessControlHandler.hasRole(DEFAULT_ADMIN_ROLE, deployer) ); assertEq( - accessControl.hasRole(ADDITIONAL_ROLE_1, deployer), - accessControlHandler.hasRole(ADDITIONAL_ROLE_1, deployer) + accessControl.hasRole(MINTER_ROLE, deployer), + accessControlHandler.hasRole(MINTER_ROLE, deployer) ); assertEq( - accessControl.hasRole(ADDITIONAL_ROLE_2, deployer), - accessControlHandler.hasRole(ADDITIONAL_ROLE_2, deployer) + accessControl.hasRole(PAUSER_ROLE, deployer), + accessControlHandler.hasRole(PAUSER_ROLE, deployer) ); } - function invariantGetRoleAdmin() public view { + function statefulFuzzGetRoleAdmin() public view { assertEq( accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE), accessControlHandler.getRoleAdmin(DEFAULT_ADMIN_ROLE) ); assertEq( - accessControl.getRoleAdmin(ADDITIONAL_ROLE_1), - accessControlHandler.getRoleAdmin(ADDITIONAL_ROLE_1) + accessControl.getRoleAdmin(MINTER_ROLE), + accessControlHandler.getRoleAdmin(MINTER_ROLE) ); assertEq( - accessControl.getRoleAdmin(ADDITIONAL_ROLE_2), - accessControlHandler.getRoleAdmin(ADDITIONAL_ROLE_2) + accessControl.getRoleAdmin(PAUSER_ROLE), + accessControlHandler.getRoleAdmin(PAUSER_ROLE) ); } } @@ -691,8 +684,8 @@ contract AccessControlInvariants is Test { contract AccessControlHandler { /* solhint-disable var-name-mixedcase */ bytes32 private immutable DEFAULT_ADMIN_ROLE; - bytes32 private immutable ADDITIONAL_ROLE_1; - bytes32 private immutable ADDITIONAL_ROLE_2; + bytes32 private immutable MINTER_ROLE; + bytes32 private immutable PAUSER_ROLE; /* solhint-enable var-name-mixedcase */ mapping(bytes32 => mapping(address => bool)) public hasRole; @@ -704,16 +697,16 @@ contract AccessControlHandler { IAccessControlExtended accessControl_, address defaultAdmin_, bytes32 adminRole_, - bytes32 additionalRole1_, - bytes32 additionalRole2_ + bytes32 minterRole_, + bytes32 pauserRole_ ) { accessControl = accessControl_; DEFAULT_ADMIN_ROLE = adminRole_; - ADDITIONAL_ROLE_1 = additionalRole1_; - ADDITIONAL_ROLE_2 = additionalRole2_; + MINTER_ROLE = minterRole_; + PAUSER_ROLE = pauserRole_; hasRole[DEFAULT_ADMIN_ROLE][defaultAdmin_] = true; - hasRole[ADDITIONAL_ROLE_1][defaultAdmin_] = true; - hasRole[ADDITIONAL_ROLE_2][defaultAdmin_] = true; + hasRole[MINTER_ROLE][defaultAdmin_] = true; + hasRole[PAUSER_ROLE][defaultAdmin_] = true; } function grantRole(bytes32 role, address account) public { diff --git a/test/auth/Ownable.t.sol b/test/auth/Ownable.t.sol index 785edc50..51153322 100644 --- a/test/auth/Ownable.t.sol +++ b/test/auth/Ownable.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -17,7 +17,10 @@ contract OwnableTest is Test { function setUp() public { ownable = IOwnable( - vyperDeployer.deployContract("src/snekmate/auth/", "Ownable") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "ownable_mock" + ) ); } @@ -27,7 +30,10 @@ contract OwnableTest is Test { vm.expectEmit(true, true, false, false); emit IOwnable.OwnershipTransferred(zeroAddress, deployer); ownableInitialEvent = IOwnable( - vyperDeployer.deployContract("src/snekmate/auth/", "Ownable") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "ownable_mock" + ) ); assertEq(ownableInitialEvent.owner(), deployer); } @@ -48,13 +54,13 @@ contract OwnableTest is Test { } function testTransferOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ownable.transfer_ownership(makeAddr("newOwner")); } function testTransferOwnershipToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("Ownable: new owner is the zero address")); + vm.expectRevert(bytes("ownable: new owner is the zero address")); ownable.transfer_ownership(zeroAddress); } @@ -70,7 +76,7 @@ contract OwnableTest is Test { } function testRenounceOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ownable.renounce_ownership(); } @@ -101,7 +107,7 @@ contract OwnableTest is Test { ) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ownable.transfer_ownership(newOwner); } @@ -127,7 +133,7 @@ contract OwnableTest is Test { function testFuzzRenounceOwnershipNonOwner(address nonOwner) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ownable.renounce_ownership(); } } @@ -142,13 +148,16 @@ contract OwnableInvariants is Test { function setUp() public { ownable = IOwnable( - vyperDeployer.deployContract("src/snekmate/auth/", "Ownable") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "ownable_mock" + ) ); ownerHandler = new OwnerHandler(ownable, deployer); targetContract(address(ownerHandler)); } - function invariantOwner() public view { + function statefulFuzzOwner() public view { assertEq(ownable.owner(), ownerHandler.owner()); } } diff --git a/test/auth/Ownable2Step.t.sol b/test/auth/Ownable2Step.t.sol index 1649d008..1c0c4faf 100644 --- a/test/auth/Ownable2Step.t.sol +++ b/test/auth/Ownable2Step.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -17,7 +17,10 @@ contract Ownable2StepTest is Test { function setUp() public { ownable2Step = IOwnable2Step( - vyperDeployer.deployContract("src/snekmate/auth/", "Ownable2Step") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "ownable_2step_mock" + ) ); } @@ -28,7 +31,10 @@ contract Ownable2StepTest is Test { vm.expectEmit(true, true, false, false); emit IOwnable2Step.OwnershipTransferred(zeroAddress, deployer); ownable2StepInitialEvent = IOwnable2Step( - vyperDeployer.deployContract("src/snekmate/auth/", "Ownable2Step") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "ownable_2step_mock" + ) ); assertEq(ownable2StepInitialEvent.owner(), deployer); assertEq(ownable2StepInitialEvent.pending_owner(), zeroAddress); @@ -52,7 +58,7 @@ contract Ownable2StepTest is Test { } function testTransferOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable2Step: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ownable2Step.transfer_ownership(makeAddr("newOwner")); } @@ -87,7 +93,7 @@ contract Ownable2StepTest is Test { assertEq(ownable2Step.owner(), oldOwner); assertEq(ownable2Step.pending_owner(), newOwner); - vm.expectRevert(bytes("Ownable2Step: caller is not the new owner")); + vm.expectRevert(bytes("ownable_2step: caller is not the new owner")); ownable2Step.accept_ownership(); vm.stopPrank(); } @@ -104,7 +110,7 @@ contract Ownable2StepTest is Test { } function testRenounceOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable2Step: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ownable2Step.renounce_ownership(); } @@ -125,7 +131,7 @@ contract Ownable2StepTest is Test { vm.stopPrank(); vm.startPrank(newOwner); - vm.expectRevert(bytes("Ownable2Step: caller is not the new owner")); + vm.expectRevert(bytes("ownable_2step: caller is not the new owner")); ownable2Step.accept_ownership(); vm.stopPrank(); } @@ -158,7 +164,7 @@ contract Ownable2StepTest is Test { ) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable2Step: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ownable2Step.transfer_ownership(newOwner); } @@ -209,7 +215,7 @@ contract Ownable2StepTest is Test { assertEq(ownable2Step.owner(), oldOwner); assertEq(ownable2Step.pending_owner(), newOwner); - vm.expectRevert(bytes("Ownable2Step: caller is not the new owner")); + vm.expectRevert(bytes("ownable_2step: caller is not the new owner")); ownable2Step.accept_ownership(); vm.stopPrank(); } @@ -245,7 +251,7 @@ contract Ownable2StepTest is Test { function testFuzzRenounceOwnershipNonOwner(address nonOwner) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable2Step: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ownable2Step.renounce_ownership(); } @@ -268,7 +274,7 @@ contract Ownable2StepTest is Test { vm.stopPrank(); vm.startPrank(newOwner); - vm.expectRevert(bytes("Ownable2Step: caller is not the new owner")); + vm.expectRevert(bytes("ownable_2step: caller is not the new owner")); ownable2Step.accept_ownership(); vm.stopPrank(); } @@ -285,7 +291,10 @@ contract Ownable2StepInvariants is Test { function setUp() public { ownable2Step = IOwnable2Step( - vyperDeployer.deployContract("src/snekmate/auth/", "Ownable2Step") + vyperDeployer.deployContract( + "src/snekmate/auth/mocks/", + "ownable_2step_mock" + ) ); owner2StepHandler = new Owner2StepHandler( ownable2Step, @@ -295,11 +304,11 @@ contract Ownable2StepInvariants is Test { targetContract(address(owner2StepHandler)); } - function invariantOwner() public view { + function statefulFuzzOwner() public view { assertEq(ownable2Step.owner(), owner2StepHandler.owner()); } - function invariantPendingOwner() public view { + function statefulFuzzPendingOwner() public view { assertEq( ownable2Step.pending_owner(), owner2StepHandler.pending_owner() diff --git a/test/auth/interfaces/IAccessControlExtended.sol b/test/auth/interfaces/IAccessControlExtended.sol index 43ab351b..1e1d565d 100644 --- a/test/auth/interfaces/IAccessControlExtended.sol +++ b/test/auth/interfaces/IAccessControlExtended.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC165} from "openzeppelin/utils/introspection/IERC165.sol"; import {IAccessControl} from "openzeppelin/access/IAccessControl.sol"; @@ -7,9 +7,9 @@ import {IAccessControl} from "openzeppelin/access/IAccessControl.sol"; interface IAccessControlExtended is IERC165, IAccessControl { function DEFAULT_ADMIN_ROLE() external pure returns (bytes32); - function ADDITIONAL_ROLE_1() external pure returns (bytes32); + function MINTER_ROLE() external pure returns (bytes32); - function ADDITIONAL_ROLE_2() external pure returns (bytes32); + function PAUSER_ROLE() external pure returns (bytes32); function set_role_admin(bytes32 role, bytes32 adminRole) external; } diff --git a/test/auth/interfaces/IOwnable.sol b/test/auth/interfaces/IOwnable.sol index 8849f155..8dd30c00 100644 --- a/test/auth/interfaces/IOwnable.sol +++ b/test/auth/interfaces/IOwnable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface IOwnable { event OwnershipTransferred( diff --git a/test/auth/interfaces/IOwnable2Step.sol b/test/auth/interfaces/IOwnable2Step.sol index 60201dfd..35cdabc3 100644 --- a/test/auth/interfaces/IOwnable2Step.sol +++ b/test/auth/interfaces/IOwnable2Step.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface IOwnable2Step { event OwnershipTransferStarted( diff --git a/test/echidna.yaml b/test/echidna.yaml new file mode 100644 index 00000000..4ea03639 --- /dev/null +++ b/test/echidna.yaml @@ -0,0 +1,17 @@ +coverage: true # Enable coverage. +corpusDir: "echidna-corpus" # Set the coverage report directory. +testMode: assertion # Enable `isAssertionMode`. +testLimit: 10000 # Set the maximum number of function calls to execute while fuzzing. +deployer: "0x10000" # Set the contract deployer address to use. +sender: ["0x10000", "0x20000", "0x30000"] # Set the sender addresses to use. +allContracts: true # Enable fuzzing of all contracts. +allowFFI: true # Enable the foreign function interface (ffi) cheatcode. +filterFunctions: # Configure the list of methods to filter. + [ + "VyperDeployer.deployContract(string,string)", + "VyperDeployer.deployContract(string,string,bytes)", + "VyperDeployer.deployContract(string,string,string,string)", + "VyperDeployer.deployContract(string,string,bytes,string,string)", + ] +filterBlacklist: true # Blacklist methods in `filterFunctions`. +cryticArgs: ["--ignore-compile"] # Disable compilation in `crytic-compile`. diff --git a/test/extensions/ERC2981.t.sol b/test/extensions/ERC2981.t.sol index 81d96f11..cba60993 100644 --- a/test/extensions/ERC2981.t.sol +++ b/test/extensions/ERC2981.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -22,7 +22,10 @@ contract ERC2981Test is Test { function setUp() public { ERC2981Extended = IERC2981Extended( - vyperDeployer.deployContract("src/snekmate/extensions/", "ERC2981") + vyperDeployer.deployContract( + "src/snekmate/extensions/mocks/", + "erc2981_mock" + ) ); } @@ -40,7 +43,10 @@ contract ERC2981Test is Test { vm.expectEmit(true, true, false, false); emit IERC2981Extended.OwnershipTransferred(zeroAddress, deployer); ERC2981ExtendedInitialEvent = IERC2981Extended( - vyperDeployer.deployContract("src/snekmate/extensions/", "ERC2981") + vyperDeployer.deployContract( + "src/snekmate/extensions/mocks/", + "erc2981_mock" + ) ); ( address receiverInitialSetup, @@ -306,7 +312,7 @@ contract ERC2981Test is Test { function testSetDefaultRoyaltyTooHighFeeNumerator() public { address owner = deployer; vm.startPrank(owner); - vm.expectRevert("ERC2981: royalty fee will exceed sale_price"); + vm.expectRevert("erc2981: royalty fee will exceed sale_price"); ERC2981Extended.set_default_royalty(makeAddr("receiver"), 11_000); vm.stopPrank(); } @@ -314,25 +320,25 @@ contract ERC2981Test is Test { function testSetDefaultRoyaltyInvalidReceiver() public { address owner = deployer; vm.startPrank(owner); - vm.expectRevert("ERC2981: invalid receiver"); + vm.expectRevert("erc2981: invalid receiver"); ERC2981Extended.set_default_royalty(zeroAddress, 10); vm.stopPrank(); } function testSetDefaultRoyaltyNonOwner() public { - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("ownable: caller is not the owner"); ERC2981Extended.set_default_royalty(zeroAddress, 10); } function testDeleteDefaultRoyaltyNonOwner() public { - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("ownable: caller is not the owner"); ERC2981Extended.delete_default_royalty(); } function testSetTokenRoyaltyTooHighFeeNumerator() public { address owner = deployer; vm.startPrank(owner); - vm.expectRevert("ERC2981: royalty fee will exceed sale_price"); + vm.expectRevert("erc2981: royalty fee will exceed sale_price"); ERC2981Extended.set_token_royalty(1, makeAddr("receiver"), 11_000); vm.stopPrank(); } @@ -340,18 +346,18 @@ contract ERC2981Test is Test { function testSetTokenRoyaltyInvalidReceiver() public { address owner = deployer; vm.startPrank(owner); - vm.expectRevert("ERC2981: invalid receiver"); + vm.expectRevert("erc2981: invalid receiver"); ERC2981Extended.set_token_royalty(1, zeroAddress, 10); vm.stopPrank(); } function testSetTokenRoyaltyNonOwner() public { - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("ownable: caller is not the owner"); ERC2981Extended.set_token_royalty(1, zeroAddress, 10); } function testResetTokenRoyaltyNonOwner() public { - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("ownable: caller is not the owner"); ERC2981Extended.reset_token_royalty(1); } @@ -371,13 +377,13 @@ contract ERC2981Test is Test { } function testTransferOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC2981Extended.transfer_ownership(makeAddr("newOwner")); } function testTransferOwnershipToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("Ownable: new owner is the zero address")); + vm.expectRevert(bytes("ownable: new owner is the zero address")); ERC2981Extended.transfer_ownership(zeroAddress); } @@ -393,7 +399,7 @@ contract ERC2981Test is Test { } function testRenounceOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC2981Extended.renounce_ownership(); } @@ -651,20 +657,20 @@ contract ERC2981Test is Test { ); address owner = deployer; vm.startPrank(owner); - vm.expectRevert("ERC2981: royalty fee will exceed sale_price"); + vm.expectRevert("erc2981: royalty fee will exceed sale_price"); ERC2981Extended.set_default_royalty(makeAddr("receiver"), feeNumerator); vm.stopPrank(); } function testFuzzSetDefaultRoyaltyNonOwner(address msgSender) public { vm.assume(msgSender != deployer); - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("ownable: caller is not the owner"); ERC2981Extended.set_default_royalty(zeroAddress, 10); } function testFuzzDeleteDefaultRoyaltyNonOwner(address msgSender) public { vm.assume(msgSender != deployer); - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("ownable: caller is not the owner"); ERC2981Extended.delete_default_royalty(); } @@ -676,7 +682,7 @@ contract ERC2981Test is Test { ); address owner = deployer; vm.startPrank(owner); - vm.expectRevert("ERC2981: royalty fee will exceed sale_price"); + vm.expectRevert("erc2981: royalty fee will exceed sale_price"); ERC2981Extended.set_token_royalty( 1, makeAddr("receiver"), @@ -689,20 +695,20 @@ contract ERC2981Test is Test { vm.assume(msgSender != deployer); address owner = deployer; vm.startPrank(owner); - vm.expectRevert("ERC2981: invalid receiver"); + vm.expectRevert("erc2981: invalid receiver"); ERC2981Extended.set_token_royalty(1, zeroAddress, 10); vm.stopPrank(); } function testFuzzSetTokenRoyaltyNonOwner(address msgSender) public { vm.assume(msgSender != deployer); - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("ownable: caller is not the owner"); ERC2981Extended.set_token_royalty(1, zeroAddress, 10); } function testFuzzResetTokenRoyaltyNonOwner(address msgSender) public { vm.assume(msgSender != deployer); - vm.expectRevert("Ownable: caller is not the owner"); + vm.expectRevert("ownable: caller is not the owner"); ERC2981Extended.reset_token_royalty(1); } @@ -733,7 +739,7 @@ contract ERC2981Test is Test { ) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC2981Extended.transfer_ownership(newOwner); } @@ -759,7 +765,7 @@ contract ERC2981Test is Test { function testFuzzRenounceOwnershipNonOwner(address nonOwner) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC2981Extended.renounce_ownership(); } } @@ -775,14 +781,17 @@ contract ERC2981Invariants is Test { function setUp() public { ERC2981Extended = IERC2981Extended( - vyperDeployer.deployContract("src/snekmate/extensions/", "ERC2981") + vyperDeployer.deployContract( + "src/snekmate/extensions/mocks/", + "erc2981_mock" + ) ); erc2981Handler = new ERC2981Handler(ERC2981Extended, deployer); targetContract(address(erc2981Handler)); targetSender(deployer); } - function invariantOwner() public view { + function statefulFuzzOwner() public view { assertEq(ERC2981Extended.owner(), erc2981Handler.owner()); } } diff --git a/test/extensions/ERC4626.t.sol b/test/extensions/ERC4626.t.sol index eb352060..2786d428 100644 --- a/test/extensions/ERC4626.t.sol +++ b/test/extensions/ERC4626.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {ERC4626Test} from "erc4626-tests/ERC4626.test.sol"; @@ -76,8 +76,8 @@ contract ERC4626VaultTest is ERC4626Test { ); ERC4626ExtendedDecimalsOffset0 = IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", argsDecimalsOffset0 ) ); @@ -104,8 +104,8 @@ contract ERC4626VaultTest is ERC4626Test { ); ERC4626ExtendedDecimalsOffset6 = IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", argsDecimalsOffset6 ) ); @@ -123,8 +123,8 @@ contract ERC4626VaultTest is ERC4626Test { ); ERC4626ExtendedDecimalsOffset12 = IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", argsDecimalsOffset12 ) ); @@ -142,8 +142,8 @@ contract ERC4626VaultTest is ERC4626Test { ); ERC4626ExtendedDecimalsOffset18 = IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", argsDecimalsOffset18 ) ); @@ -196,8 +196,8 @@ contract ERC4626VaultTest is ERC4626Test { // solhint-disable-next-line var-name-mixedcase IERC4626Extended ERC4626ExtendedDecimalsOffsetEOA = IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", argsDecimalsOffsetEOA ) ); @@ -223,8 +223,8 @@ contract ERC4626VaultTest is ERC4626Test { // solhint-disable-next-line var-name-mixedcase IERC4626Extended ERC4626ExtendedDecimalsOffsetNoDecimals = IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", argsDecimalsOffsetNoDecimals ) ); @@ -251,8 +251,8 @@ contract ERC4626VaultTest is ERC4626Test { // solhint-disable-next-line var-name-mixedcase IERC4626Extended ERC4626ExtendedDecimalsOffsetTooHighDecimals = IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", argsDecimalsOffsetTooHighDecimals ) ); @@ -285,8 +285,8 @@ contract ERC4626VaultTest is ERC4626Test { vm.expectRevert(); IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", argsDecimalsOffsetOverflow ) ); @@ -1463,7 +1463,7 @@ contract ERC4626VaultTest is ERC4626Test { underlying.mint(self, type(uint8).max); underlying.approve(ERC4626ExtendedDecimalsOffset0Addr, type(uint8).max); ERC4626ExtendedDecimalsOffset0.deposit(type(uint8).max, self); - vm.expectRevert(bytes("ERC4626: withdraw more than maximum")); + vm.expectRevert(bytes("erc4626: withdraw more than maximum")); ERC4626ExtendedDecimalsOffset0.withdraw( uint256(type(uint8).max) + 1, self, @@ -1475,7 +1475,7 @@ contract ERC4626VaultTest is ERC4626Test { underlying.mint(self, type(uint8).max); underlying.approve(ERC4626ExtendedDecimalsOffset0Addr, type(uint8).max); ERC4626ExtendedDecimalsOffset0.deposit(type(uint8).max, self); - vm.expectRevert(bytes("ERC20: insufficient allowance")); + vm.expectRevert(bytes("erc20: insufficient allowance")); vm.prank(makeAddr("otherAccount")); ERC4626ExtendedDecimalsOffset0.withdraw(type(uint8).max, self, self); } @@ -1484,7 +1484,7 @@ contract ERC4626VaultTest is ERC4626Test { underlying.mint(self, type(uint16).max); underlying.approve(ERC4626ExtendedDecimalsOffset0Addr, type(uint8).max); ERC4626ExtendedDecimalsOffset0.deposit(type(uint8).max, self); - vm.expectRevert(bytes("ERC4626: redeem more than maximum")); + vm.expectRevert(bytes("erc4626: redeem more than maximum")); ERC4626ExtendedDecimalsOffset0.redeem( uint256(type(uint8).max) + 1, self, @@ -1493,12 +1493,12 @@ contract ERC4626VaultTest is ERC4626Test { } function testWithdrawWithNoAssets() public { - vm.expectRevert(bytes("ERC4626: withdraw more than maximum")); + vm.expectRevert(bytes("erc4626: withdraw more than maximum")); ERC4626ExtendedDecimalsOffset0.withdraw(type(uint8).max, self, self); } function testRedeemWithNoShares() public { - vm.expectRevert(bytes("ERC4626: redeem more than maximum")); + vm.expectRevert(bytes("erc4626: redeem more than maximum")); ERC4626ExtendedDecimalsOffset0.redeem(type(uint8).max, self, self); } @@ -1586,7 +1586,7 @@ contract ERC4626VaultTest is ERC4626Test { vm.stopPrank(); vm.startPrank(bob); - vm.expectRevert(bytes("ERC4626: withdraw more than maximum")); + vm.expectRevert(bytes("erc4626: withdraw more than maximum")); ERC4626ExtendedDecimalsOffset0.withdraw(amount, alice, bob); vm.stopPrank(); } @@ -1674,7 +1674,7 @@ contract ERC4626VaultTest is ERC4626Test { r, s ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC4626ExtendedDecimalsOffset0.permit( owner, spender, @@ -1713,7 +1713,7 @@ contract ERC4626VaultTest is ERC4626Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC4626ExtendedDecimalsOffset0.permit( owner, spender, @@ -1759,7 +1759,7 @@ contract ERC4626VaultTest is ERC4626Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC4626ExtendedDecimalsOffset0.permit( owner, spender, @@ -1798,7 +1798,7 @@ contract ERC4626VaultTest is ERC4626Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC4626ExtendedDecimalsOffset0.permit( owner, spender, @@ -1837,7 +1837,7 @@ contract ERC4626VaultTest is ERC4626Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: expired deadline")); + vm.expectRevert(bytes("erc20: expired deadline")); ERC4626ExtendedDecimalsOffset0.permit( owner, spender, @@ -1984,7 +1984,7 @@ contract ERC4626VaultTest is ERC4626Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC4626ExtendedDecimalsOffset0.permit( ownerAddr, spenderAddr, @@ -2090,8 +2090,8 @@ contract ERC4626VaultInvariants is Test { ); ERC4626Extended = IERC4626Extended( vyperDeployer.deployContract( - "src/snekmate/extensions/", - "ERC4626", + "src/snekmate/extensions/mocks/", + "erc4626_mock", args ) ); @@ -2100,14 +2100,14 @@ contract ERC4626VaultInvariants is Test { targetSender(deployer); } - function invariantTotalSupply() public view { + function statefulFuzzTotalSupply() public view { assertEq( ERC4626Extended.totalSupply(), erc4626VaultHandler.totalSupply() ); } - function invariantTotalAssets() public view { + function statefulFuzzTotalAssets() public view { assertEq( ERC4626Extended.totalAssets(), erc4626VaultHandler.totalAssets() diff --git a/test/extensions/interfaces/IERC2981Extended.sol b/test/extensions/interfaces/IERC2981Extended.sol index 8d07f16d..53cc4aa6 100644 --- a/test/extensions/interfaces/IERC2981Extended.sol +++ b/test/extensions/interfaces/IERC2981Extended.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC2981} from "openzeppelin/interfaces/IERC2981.sol"; diff --git a/test/extensions/interfaces/IERC4626Extended.sol b/test/extensions/interfaces/IERC4626Extended.sol index 6054351d..8b9c5838 100644 --- a/test/extensions/interfaces/IERC4626Extended.sol +++ b/test/extensions/interfaces/IERC4626Extended.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC20Metadata} from "openzeppelin/token/ERC20/extensions/IERC20Metadata.sol"; import {IERC20Permit} from "openzeppelin/token/ERC20/extensions/IERC20Permit.sol"; diff --git a/test/extensions/mocks/ERC20ExcessDecimalsMock.sol b/test/extensions/mocks/ERC20ExcessDecimalsMock.sol index 6de39195..bcd85d32 100644 --- a/test/extensions/mocks/ERC20ExcessDecimalsMock.sol +++ b/test/extensions/mocks/ERC20ExcessDecimalsMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; /** * @title ERC20ExcessDecimalsMock diff --git a/test/governance/TimelockController.t.sol b/test/governance/TimelockController.t.sol index c6797e9c..56d6b150 100644 --- a/test/governance/TimelockController.t.sol +++ b/test/governance/TimelockController.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -18,9 +18,9 @@ import {ITimelockController} from "./interfaces/ITimelockController.sol"; /** * @dev The standard access control functionalities are not tested as they - * were taken 1:1 from `AccessControl.vy`. See `AccessControl.t.sol` for the - * corresponding tests. However, please integrate these tests into your own - * test suite before deploying `TimelockController` into production! + * are imported via the `access_control` module. See `AccessControl.t.sol` + * for the corresponding tests. However, please integrate these tests into + * your own test suite before deploying `TimelockController` into production! */ contract TimelockControllerTest is Test { bytes32 private constant DEFAULT_ADMIN_ROLE = bytes32(0); @@ -102,8 +102,8 @@ contract TimelockControllerTest is Test { bytes memory args = abi.encode(MIN_DELAY, proposers_, executors_, self); timelockController = ITimelockController( vyperDeployer.deployContract( - "src/snekmate/governance/", - "TimelockController", + "src/snekmate/governance/mocks/", + "timelock_controller_mock", args ) ); @@ -272,8 +272,8 @@ contract TimelockControllerTest is Test { emit ITimelockController.MinimumDelayChange(0, MIN_DELAY); timelockControllerInitialEventEmptyAdmin = ITimelockController( vyperDeployer.deployContract( - "src/snekmate/governance/", - "TimelockController", + "src/snekmate/governance/mocks/", + "timelock_controller_mock", argsEmptyAdmin ) ); @@ -455,8 +455,8 @@ contract TimelockControllerTest is Test { emit ITimelockController.MinimumDelayChange(0, MIN_DELAY); timelockControllerInitialEventNonEmptyAdmin = ITimelockController( vyperDeployer.deployContract( - "src/snekmate/governance/", - "TimelockController", + "src/snekmate/governance/mocks/", + "timelock_controller_mock", argsNonEmptyAdmin ) ); @@ -658,8 +658,8 @@ contract TimelockControllerTest is Test { function testHashOperation() public view { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -682,8 +682,8 @@ contract TimelockControllerTest is Test { function testScheduleAndExecuteWithEmptySalt() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -755,8 +755,8 @@ contract TimelockControllerTest is Test { function testScheduleAndExecuteWithNonEmptySalt() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -857,7 +857,7 @@ contract TimelockControllerTest is Test { EMPTY_SALT, MIN_DELAY ); - vm.expectRevert("TimelockController: operation already scheduled"); + vm.expectRevert("timelock_controller: operation already scheduled"); timelockController.schedule( target, amount, @@ -870,7 +870,7 @@ contract TimelockControllerTest is Test { } function testOperationInsufficientDelay() public { - vm.expectRevert("TimelockController: insufficient delay"); + vm.expectRevert("timelock_controller: insufficient delay"); vm.prank(PROPOSER_ONE); timelockController.schedule( target, @@ -1084,7 +1084,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY - 2 days); - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); vm.prank(EXECUTOR_ONE); timelockController.execute( zeroAddress, @@ -1097,8 +1097,8 @@ contract TimelockControllerTest is Test { function testOperationPredecessorNotExecuted() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1159,15 +1159,15 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY + 2 days); - vm.expectRevert("TimelockController: missing dependency"); + vm.expectRevert("timelock_controller: missing dependency"); vm.prank(EXECUTOR_ONE); timelockController.execute(target, amount, payload, operationId1, SALT); } function testOperationPredecessorNotScheduled() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1210,15 +1210,15 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY + 2 days); - vm.expectRevert("TimelockController: missing dependency"); + vm.expectRevert("timelock_controller: missing dependency"); vm.prank(EXECUTOR_ONE); timelockController.execute(target, amount, payload, operationId1, SALT); } function testOperationPredecessorInvalid() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1255,7 +1255,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY + 2 days); - vm.expectRevert("TimelockController: missing dependency"); + vm.expectRevert("timelock_controller: missing dependency"); vm.prank(EXECUTOR_ONE); timelockController.execute( target, @@ -1338,7 +1338,7 @@ contract TimelockControllerTest is Test { NO_PREDECESSOR, EMPTY_SALT ); - vm.expectRevert("TimelockController: underlying transaction reverted"); + vm.expectRevert("timelock_controller: underlying transaction reverted"); timelockController.execute( target, amount, @@ -1351,8 +1351,8 @@ contract TimelockControllerTest is Test { function testOperationPredecessorMultipleNotExecuted() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1402,7 +1402,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY + 2 days); - vm.expectRevert("TimelockController: missing dependency"); + vm.expectRevert("timelock_controller: missing dependency"); vm.prank(EXECUTOR_ONE); timelockController.execute( target, @@ -1415,8 +1415,8 @@ contract TimelockControllerTest is Test { function testOperationCancelFinished() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1471,14 +1471,14 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.prank(PROPOSER_ONE); - vm.expectRevert("TimelockController: operation cannot be cancelled"); + vm.expectRevert("timelock_controller: operation cannot be cancelled"); timelockController.cancel(operationId); } function testOperationPendingIfNotYetExecuted() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1517,8 +1517,8 @@ contract TimelockControllerTest is Test { function testOperationPendingIfExecuted() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1576,8 +1576,8 @@ contract TimelockControllerTest is Test { function testOperationReadyOnTheExecutionTime() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1617,8 +1617,8 @@ contract TimelockControllerTest is Test { function testOperationReadyAfterTheExecutionTime() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1658,8 +1658,8 @@ contract TimelockControllerTest is Test { function testOperationReadyBeforeTheExecutionTime() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1699,8 +1699,8 @@ contract TimelockControllerTest is Test { function testOperationHasBeenExecuted() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1759,8 +1759,8 @@ contract TimelockControllerTest is Test { function testOperationHasNotBeenExecuted() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1799,8 +1799,8 @@ contract TimelockControllerTest is Test { function testOperationTimestampHasNotBeenExecuted() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1842,8 +1842,8 @@ contract TimelockControllerTest is Test { function testOperationTimestampHasBeenExecuted() public { uint256 amount = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -1904,8 +1904,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -1938,8 +1938,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2022,8 +2022,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2108,8 +2108,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2145,7 +2145,7 @@ contract TimelockControllerTest is Test { EMPTY_SALT, MIN_DELAY ); - vm.expectRevert("TimelockController: operation already scheduled"); + vm.expectRevert("timelock_controller: operation already scheduled"); timelockController.schedule_batch( targets, amounts, @@ -2162,15 +2162,15 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, value ); - vm.expectRevert("TimelockController: insufficient delay"); + vm.expectRevert("timelock_controller: insufficient delay"); vm.prank(PROPOSER_ONE); timelockController.schedule_batch( targets, @@ -2187,8 +2187,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2264,8 +2264,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2321,8 +2321,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2361,7 +2361,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY - 2 days); - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); vm.prank(EXECUTOR_ONE); timelockController.execute_batch( targets, @@ -2377,8 +2377,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2444,7 +2444,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY + 2 days); - vm.expectRevert("TimelockController: missing dependency"); + vm.expectRevert("timelock_controller: missing dependency"); vm.prank(EXECUTOR_ONE); timelockController.execute_batch( targets, @@ -2460,8 +2460,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2507,7 +2507,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY + 2 days); - vm.expectRevert("TimelockController: missing dependency"); + vm.expectRevert("timelock_controller: missing dependency"); vm.prank(EXECUTOR_ONE); timelockController.execute_batch( targets, @@ -2523,8 +2523,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2564,7 +2564,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY + 2 days); - vm.expectRevert("TimelockController: missing dependency"); + vm.expectRevert("timelock_controller: missing dependency"); vm.prank(EXECUTOR_ONE); timelockController.execute_batch( targets, @@ -2656,7 +2656,7 @@ contract TimelockControllerTest is Test { NO_PREDECESSOR, EMPTY_SALT ); - vm.expectRevert("TimelockController: underlying transaction reverted"); + vm.expectRevert("timelock_controller: underlying transaction reverted"); timelockController.execute_batch( targets, amounts, @@ -2672,8 +2672,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2725,7 +2725,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.warp(block.timestamp + MIN_DELAY + 2 days); - vm.expectRevert("TimelockController: missing dependency"); + vm.expectRevert("timelock_controller: missing dependency"); vm.prank(EXECUTOR_ONE); timelockController.execute_batch( targets, @@ -2741,8 +2741,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2802,7 +2802,7 @@ contract TimelockControllerTest is Test { vm.stopPrank(); vm.prank(PROPOSER_ONE); - vm.expectRevert("TimelockController: operation cannot be cancelled"); + vm.expectRevert("timelock_controller: operation cannot be cancelled"); timelockController.cancel(batchedOperationId); } @@ -2811,8 +2811,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2857,8 +2857,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2926,8 +2926,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -2973,8 +2973,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -3020,8 +3020,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -3067,8 +3067,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -3135,8 +3135,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -3181,8 +3181,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -3230,8 +3230,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -3313,7 +3313,7 @@ contract TimelockControllerTest is Test { } function testRevertWhenNotTimelock() public { - vm.expectRevert("TimelockController: caller must be timelock"); + vm.expectRevert("timelock_controller: caller must be timelock"); vm.prank(STRANGER); timelockController.update_delay(3 days); } @@ -3322,7 +3322,7 @@ contract TimelockControllerTest is Test { address[] memory targets = new address[](0); uint256[] memory amounts = new uint256[](0); bytes[] memory payloads = new bytes[](0); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(self); timelockController.schedule_batch( targets, @@ -3335,7 +3335,7 @@ contract TimelockControllerTest is Test { } function testAdminCannotSchedule() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(self); timelockController.schedule( zeroAddress, @@ -3352,7 +3352,7 @@ contract TimelockControllerTest is Test { uint256[] memory amounts = new uint256[](0); bytes[] memory payloads = new bytes[](0); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(self); timelockController.execute_batch( targets, @@ -3364,7 +3364,7 @@ contract TimelockControllerTest is Test { } function testAdminCannotExecute() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(self); timelockController.execute( zeroAddress, @@ -3376,7 +3376,7 @@ contract TimelockControllerTest is Test { } function testAdminCannotCancel() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(self); timelockController.cancel(EMPTY_SALT); } @@ -3437,7 +3437,7 @@ contract TimelockControllerTest is Test { uint256[] memory amounts = new uint256[](0); bytes[] memory payloads = new bytes[](0); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(PROPOSER_ONE); timelockController.execute_batch( targets, @@ -3447,7 +3447,7 @@ contract TimelockControllerTest is Test { EMPTY_SALT ); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(PROPOSER_TWO); timelockController.execute_batch( targets, @@ -3459,7 +3459,7 @@ contract TimelockControllerTest is Test { } function testProposerCannotExecute() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(PROPOSER_ONE); timelockController.execute( zeroAddress, @@ -3469,7 +3469,7 @@ contract TimelockControllerTest is Test { EMPTY_SALT ); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(PROPOSER_TWO); timelockController.execute( zeroAddress, @@ -3481,11 +3481,11 @@ contract TimelockControllerTest is Test { } function testProposerCanCancel() public { - vm.expectRevert("TimelockController: operation cannot be cancelled"); + vm.expectRevert("timelock_controller: operation cannot be cancelled"); vm.prank(PROPOSER_ONE); timelockController.cancel(EMPTY_SALT); - vm.expectRevert("TimelockController: operation cannot be cancelled"); + vm.expectRevert("timelock_controller: operation cannot be cancelled"); vm.prank(PROPOSER_TWO); timelockController.cancel(EMPTY_SALT); } @@ -3495,7 +3495,7 @@ contract TimelockControllerTest is Test { uint256[] memory amounts = new uint256[](0); bytes[] memory payloads = new bytes[](0); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(EXECUTOR_ONE); timelockController.schedule_batch( targets, @@ -3506,7 +3506,7 @@ contract TimelockControllerTest is Test { MIN_DELAY ); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(EXECUTOR_TWO); timelockController.schedule_batch( targets, @@ -3519,7 +3519,7 @@ contract TimelockControllerTest is Test { } function testExecutorCannotSchedule() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(EXECUTOR_ONE); timelockController.schedule( zeroAddress, @@ -3530,7 +3530,7 @@ contract TimelockControllerTest is Test { MIN_DELAY ); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(EXECUTOR_TWO); timelockController.schedule( zeroAddress, @@ -3547,7 +3547,7 @@ contract TimelockControllerTest is Test { uint256[] memory amounts = new uint256[](0); bytes[] memory payloads = new bytes[](0); - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); vm.prank(EXECUTOR_ONE); timelockController.execute_batch( targets, @@ -3557,7 +3557,7 @@ contract TimelockControllerTest is Test { EMPTY_SALT ); - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); vm.prank(EXECUTOR_TWO); timelockController.execute_batch( targets, @@ -3569,7 +3569,7 @@ contract TimelockControllerTest is Test { } function testExecutorCanExecute() public { - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); vm.prank(EXECUTOR_ONE); timelockController.execute( zeroAddress, @@ -3579,7 +3579,7 @@ contract TimelockControllerTest is Test { EMPTY_SALT ); - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); vm.prank(EXECUTOR_TWO); timelockController.execute( zeroAddress, @@ -3591,11 +3591,11 @@ contract TimelockControllerTest is Test { } function testExecutorCannotCancel() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(EXECUTOR_ONE); timelockController.cancel(EMPTY_SALT); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(EXECUTOR_TWO); timelockController.cancel(EMPTY_SALT); } @@ -3605,7 +3605,7 @@ contract TimelockControllerTest is Test { uint256[] memory amounts = new uint256[](0); bytes[] memory payloads = new bytes[](0); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(STRANGER); timelockController.schedule_batch( targets, @@ -3618,7 +3618,7 @@ contract TimelockControllerTest is Test { } function testStrangerCannotSchedule() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(STRANGER); timelockController.schedule( zeroAddress, @@ -3635,7 +3635,7 @@ contract TimelockControllerTest is Test { uint256[] memory amounts = new uint256[](0); bytes[] memory payloads = new bytes[](0); - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(STRANGER); timelockController.execute_batch( targets, @@ -3647,7 +3647,7 @@ contract TimelockControllerTest is Test { } function testStrangerCannotExecute() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(STRANGER); timelockController.execute( zeroAddress, @@ -3659,7 +3659,7 @@ contract TimelockControllerTest is Test { } function testStrangerCannotCancel() public { - vm.expectRevert("AccessControl: account is missing role"); + vm.expectRevert("access_control: account is missing role"); vm.prank(STRANGER); timelockController.cancel(EMPTY_SALT); } @@ -3669,8 +3669,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = 0; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -3858,7 +3858,11 @@ contract TimelockControllerTest is Test { "1" ); erc721Mock = IERC721Extended( - vyperDeployer.deployContract("src/snekmate/tokens/", "ERC721", args) + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc721_mock", + args + ) ); vm.startPrank(deployer); erc721Mock.safe_mint(timelockControllerAddr, "my_awesome_nft_uri_1"); @@ -3933,8 +3937,8 @@ contract TimelockControllerTest is Test { bytes memory args = abi.encode("https://www.wagmi.xyz/"); erc1155Mock = IERC1155Extended( vyperDeployer.deployContract( - "src/snekmate/tokens/", - "ERC1155", + "src/snekmate/tokens/mocks/", + "erc1155_mock", args ) ); @@ -4049,8 +4053,8 @@ contract TimelockControllerTest is Test { function testFuzzOperationValue(uint256 amount) public { amount = bound(amount, 0, type(uint64).max); - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes memory payload = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, slot, @@ -4136,8 +4140,8 @@ contract TimelockControllerTest is Test { targets[0] = target; uint256[] memory amounts = new uint256[](1); amounts[0] = amount; - bytes32 slot = bytes32(uint256(1337)); - bytes32 value = bytes32(uint256(6699)); + bytes32 slot = bytes32(uint256(1_337)); + bytes32 value = bytes32(uint256(6_699)); bytes[] memory payloads = new bytes[](1); payloads[0] = abi.encodeWithSelector( callReceiverMock.mockFunctionWritesStorage.selector, @@ -4225,8 +4229,8 @@ contract TimelockControllerInvariants is Test { bytes memory args = abi.encode(minDelay, proposers, executors, self); timelockController = ITimelockController( vyperDeployer.deployContract( - "src/snekmate/governance/", - "TimelockController", + "src/snekmate/governance/mocks/", + "timelock_controller_mock", args ) ); @@ -4256,7 +4260,7 @@ contract TimelockControllerInvariants is Test { * @dev The number of scheduled transactions cannot exceed the number of * executed transactions. */ - function invariantExecutedLessThanOrEqualToScheduled() public view { + function statefulFuzzExecutedLessThanOrEqualToScheduled() public view { assertTrue( timelockControllerHandler.executeCount() <= timelockControllerHandler.scheduleCount() @@ -4266,7 +4270,7 @@ contract TimelockControllerInvariants is Test { /** * @dev The number of proposals executed must match the count number. */ - function invariantProposalsExecutedMatchCount() public view { + function statefulFuzzProposalsExecutedMatchCount() public view { assertEq( timelockControllerHandler.executeCount(), timelockControllerHandler.counter() @@ -4276,13 +4280,13 @@ contract TimelockControllerInvariants is Test { /** * @dev Proposals can only be scheduled and executed once. */ - function invariantOnceProposalExecution() public { + function statefulFuzzOnceProposalExecution() public { uint256[] memory executed = timelockControllerHandler.getExecuted(); for (uint256 i = 0; i < executed.length; ++i) { /** * @dev Ensure that the executed proposal cannot be executed again. */ - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); timelockController.execute( timelockControllerHandlerAddr, 0, @@ -4299,7 +4303,7 @@ contract TimelockControllerInvariants is Test { * @dev The sum of the executed proposals and the cancelled proposals must * be less than or equal to the number of scheduled proposals. */ - function invariantSumOfProposals() public view { + function statefulFuzzSumOfProposals() public view { assertTrue( (timelockControllerHandler.cancelCount() + timelockControllerHandler.executeCount()) <= @@ -4310,7 +4314,7 @@ contract TimelockControllerInvariants is Test { /** * @dev The executed proposals cannot be cancelled. */ - function invariantExecutedProposalCancellation() public { + function statefulFuzzExecutedProposalCancellation() public { bytes32 operationId; uint256[] memory executed = timelockControllerHandler.getExecuted(); for (uint256 i = 0; i < executed.length; ++i) { @@ -4327,7 +4331,7 @@ contract TimelockControllerInvariants is Test { * @dev Ensure that the executed proposal cannot be cancelled. */ vm.expectRevert( - "TimelockController: operation cannot be cancelled" + "timelock_controller: operation cannot be cancelled" ); timelockController.cancel(operationId); } @@ -4336,7 +4340,7 @@ contract TimelockControllerInvariants is Test { /** * @dev The execution of a proposal that has been cancelled is not possible. */ - function invariantExecutingCancelledProposal() public { + function statefulFuzzExecutingCancelledProposal() public { bool isPending; uint256[] memory cancelled = timelockControllerHandler.getCancelled(); uint256[] memory pending = timelockControllerHandler.getPending(); @@ -4354,7 +4358,7 @@ contract TimelockControllerInvariants is Test { /** * @dev Ensure that the cancelled proposal cannot be executed. */ - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); timelockController.execute( timelockControllerHandlerAddr, 0, @@ -4372,14 +4376,14 @@ contract TimelockControllerInvariants is Test { /** * @dev The execution of a proposal that is not ready is not possible. */ - function invariantExecutingNotReadyProposal() public { + function statefulFuzzExecutingNotReadyProposal() public { vm.warp(initialTimestamp); uint256[] memory pending = timelockControllerHandler.getPending(); for (uint256 i = 0; i < pending.length; ++i) { /** * @dev Ensure that the pending proposal cannot be executed. */ - vm.expectRevert("TimelockController: operation is not ready"); + vm.expectRevert("timelock_controller: operation is not ready"); timelockController.execute( timelockControllerHandlerAddr, 0, diff --git a/test/governance/interfaces/ITimelockController.sol b/test/governance/interfaces/ITimelockController.sol index e11ac745..cb8012b2 100644 --- a/test/governance/interfaces/ITimelockController.sol +++ b/test/governance/interfaces/ITimelockController.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC721Receiver} from "openzeppelin/token/ERC721/IERC721Receiver.sol"; import {IERC1155Receiver} from "openzeppelin/token/ERC1155/IERC1155Receiver.sol"; @@ -67,9 +67,10 @@ interface ITimelockController is function is_operation_done(bytes32 id) external view returns (bool); /** - * @dev As Enums are handled differently in Vyper and Solidity (see https://x.com/pcaversaccio/status/1626514029094047747), - * we directly return the underlying Vyper type `uint256` (instead of `OperationState`) - * for Enums for ease of testing. + * @dev As Flags (a.k.a. Enums) are handled differently in Vyper and Solidity + * (see https://x.com/pcaversaccio/status/1626514029094047747), we directly + * return the underlying Vyper type `uint256` (instead of `OperationState`) for + * Flags for ease of testing. */ function get_operation_state(bytes32 id) external view returns (uint256); diff --git a/test/governance/mocks/CallReceiverMock.sol b/test/governance/mocks/CallReceiverMock.sol index 65b3f5a6..21bd80c5 100644 --- a/test/governance/mocks/CallReceiverMock.sol +++ b/test/governance/mocks/CallReceiverMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; /** * @title CallReceiverMock @@ -94,7 +94,7 @@ contract CallReceiverMock { bytes32 value ) public payable returns (string memory) { // solhint-disable-next-line no-inline-assembly - assembly { + assembly ("memory-safe") { sstore(slot, value) } return _retValue; diff --git a/test/halmos.toml b/test/halmos.toml new file mode 100644 index 00000000..019305bc --- /dev/null +++ b/test/halmos.toml @@ -0,0 +1,15 @@ +[global] +# Test settings. +function = "testHalmos" # Run tests matching the given prefix. +storage-layout = "generic" # Set the generic storage layout model. +test-parallel = true # Run tests in parallel. +early-exit = true # Stop after a counterexample is found. +ffi = true # Enable the foreign function interface (ffi) cheatcode. + +# Debugging settings. +statistics = true # Print the statistics. +verbose = 1 # Set the verbosity level for the tests. + +# Solver settings. +solver-command = "yices-smt2" # Use the Yices 2 SMT solver. +solver-parallel = true # Run assertion solvers in parallel. diff --git a/test/tokens/ERC1155.t.sol b/test/tokens/ERC1155.t.sol index 664e8612..24860320 100644 --- a/test/tokens/ERC1155.t.sol +++ b/test/tokens/ERC1155.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -32,8 +32,8 @@ contract ERC1155Test is Test { bytes memory args = abi.encode(_BASE_URI); ERC1155Extended = IERC1155Extended( vyperDeployer.deployContract( - "src/snekmate/tokens/", - "ERC1155", + "src/snekmate/tokens/mocks/", + "erc1155_mock", args ) ); @@ -58,8 +58,8 @@ contract ERC1155Test is Test { bytes memory args = abi.encode(_BASE_URI); ERC1155ExtendedInitialEvent = IERC1155Extended( vyperDeployer.deployContract( - "src/snekmate/tokens/", - "ERC1155", + "src/snekmate/tokens/mocks/", + "erc1155_mock", args ) ); @@ -138,11 +138,6 @@ contract ERC1155Test is Test { assertEq(ERC1155Extended.balanceOf(makeAddr("thirdOwner"), 2), 0); } - function testBalanceOfZeroAddress() public { - vm.expectRevert(bytes("ERC1155: address zero is not a valid owner")); - ERC1155Extended.balanceOf(zeroAddress, 0); - } - function testBalanceOfBatchCase1() public { address firstOwner = makeAddr("firstOwner"); address secondOwner = makeAddr("secondOwner"); @@ -255,7 +250,7 @@ contract ERC1155Test is Test { owners1[0] = makeAddr("firstOwner"); owners1[1] = makeAddr("secondAddr"); ids1[0] = 0; - vm.expectRevert(bytes("ERC1155: owners and ids length mismatch")); + vm.expectRevert(bytes("erc1155: owners and ids length mismatch")); ERC1155Extended.balanceOfBatch(owners1, ids1); address[] memory owners2 = new address[](1); @@ -263,19 +258,10 @@ contract ERC1155Test is Test { owners2[0] = makeAddr("thirdOwner"); ids2[0] = 0; ids2[1] = 1; - vm.expectRevert(bytes("ERC1155: owners and ids length mismatch")); + vm.expectRevert(bytes("erc1155: owners and ids length mismatch")); ERC1155Extended.balanceOfBatch(owners2, ids2); } - function testBalanceOfBatchZeroAddress() public { - address[] memory owners = new address[](1); - uint256[] memory ids = new uint256[](1); - owners[0] = zeroAddress; - ids[0] = 0; - vm.expectRevert(bytes("ERC1155: address zero is not a valid owner")); - ERC1155Extended.balanceOfBatch(owners, ids); - } - function testSetApprovalForAllSuccess() public { address owner = makeAddr("owner"); address operator = makeAddr("operator"); @@ -314,7 +300,7 @@ contract ERC1155Test is Test { function testSetApprovalForAllToSelf() public { address owner = makeAddr("owner"); - vm.expectRevert(bytes("ERC1155: setting approval status for self")); + vm.expectRevert(bytes("erc1155: setting approval status for self")); vm.prank(owner); ERC1155Extended.setApprovalForAll(owner, true); } @@ -393,7 +379,7 @@ contract ERC1155Test is Test { vm.startPrank(operator); vm.expectRevert( - bytes("ERC1155: caller is not token owner or approved") + bytes("erc1155: caller is not token owner or approved") ); ERC1155Extended.safeTransferFrom(owner, receiver, id1, amount1, data); vm.stopPrank(); @@ -544,7 +530,7 @@ contract ERC1155Test is Test { vm.startPrank(owner); vm.expectRevert( - bytes("ERC1155: transfer to non-ERC1155Receiver implementer") + bytes("erc1155: transfer to non-IERC1155Receiver implementer") ); ERC1155Extended.safeTransferFrom(owner, receiver, id1, amount1, data); vm.stopPrank(); @@ -559,7 +545,7 @@ contract ERC1155Test is Test { vm.startPrank(operator); vm.expectRevert( - bytes("ERC1155: transfer to non-ERC1155Receiver implementer") + bytes("erc1155: transfer to non-IERC1155Receiver implementer") ); ERC1155Extended.safeTransferFrom(owner, receiver, id2, amount2, data); vm.stopPrank(); @@ -650,7 +636,7 @@ contract ERC1155Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC1155: insufficient balance for transfer")); + vm.expectRevert(bytes("erc1155: insufficient balance for transfer")); ERC1155Extended.safeTransferFrom( owner, makeAddr("to"), @@ -671,7 +657,7 @@ contract ERC1155Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC1155: transfer to the zero address")); + vm.expectRevert(bytes("erc1155: transfer to the zero address")); ERC1155Extended.safeTransferFrom(owner, zeroAddress, id, amount, data); vm.stopPrank(); } @@ -782,7 +768,7 @@ contract ERC1155Test is Test { vm.startPrank(operator); vm.expectRevert( - bytes("ERC1155: caller is not token owner or approved") + bytes("erc1155: caller is not token owner or approved") ); ERC1155Extended.safeBatchTransferFrom( owner, @@ -940,7 +926,7 @@ contract ERC1155Test is Test { vm.startPrank(owner); vm.expectRevert( - bytes("ERC1155: transfer to non-ERC1155Receiver implementer") + bytes("erc1155: transfer to non-IERC1155Receiver implementer") ); ERC1155Extended.safeBatchTransferFrom( owner, @@ -1105,7 +1091,7 @@ contract ERC1155Test is Test { vm.startPrank(owner); ++amounts[3]; - vm.expectRevert(bytes("ERC1155: insufficient balance for transfer")); + vm.expectRevert(bytes("erc1155: insufficient balance for transfer")); ERC1155Extended.safeBatchTransferFrom( owner, makeAddr("to"), @@ -1141,7 +1127,7 @@ contract ERC1155Test is Test { amounts2[2] = 20; vm.startPrank(owner); - vm.expectRevert(bytes("ERC1155: ids and amounts length mismatch")); + vm.expectRevert(bytes("erc1155: ids and amounts length mismatch")); ERC1155Extended.safeBatchTransferFrom( owner, receiver, @@ -1149,7 +1135,7 @@ contract ERC1155Test is Test { amounts1, data ); - vm.expectRevert(bytes("ERC1155: ids and amounts length mismatch")); + vm.expectRevert(bytes("erc1155: ids and amounts length mismatch")); ERC1155Extended.safeBatchTransferFrom( owner, receiver, @@ -1180,7 +1166,7 @@ contract ERC1155Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC1155: transfer to the zero address")); + vm.expectRevert(bytes("erc1155: transfer to the zero address")); ERC1155Extended.safeBatchTransferFrom( owner, zeroAddress, @@ -1206,8 +1192,8 @@ contract ERC1155Test is Test { bytes memory args = abi.encode(""); ERC1155ExtendedNoBaseURI = IERC1155Extended( vyperDeployer.deployContract( - "src/snekmate/tokens/", - "ERC1155", + "src/snekmate/tokens/mocks/", + "erc1155_mock", args ) ); @@ -1230,8 +1216,8 @@ contract ERC1155Test is Test { bytes memory args = abi.encode(""); ERC1155ExtendedNoBaseURI = IERC1155Extended( vyperDeployer.deployContract( - "src/snekmate/tokens/", - "ERC1155", + "src/snekmate/tokens/mocks/", + "erc1155_mock", args ) ); @@ -1266,7 +1252,7 @@ contract ERC1155Test is Test { } function testSetUriNonMinter() public { - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc1155: access is denied")); vm.prank(makeAddr("nonOwner")); ERC1155Extended.set_uri(1, "my_awesome_uri"); } @@ -1515,7 +1501,7 @@ contract ERC1155Test is Test { vm.startPrank(operator); vm.expectRevert( - bytes("ERC1155: caller is not token owner or approved") + bytes("erc1155: caller is not token owner or approved") ); ERC1155Extended.burn(owner, id1, burnAmount); vm.stopPrank(); @@ -1524,7 +1510,7 @@ contract ERC1155Test is Test { function testBurnFromZeroAddress() public { address owner = zeroAddress; vm.prank(owner); - vm.expectRevert(bytes("ERC1155: burn from the zero address")); + vm.expectRevert(bytes("erc1155: burn from the zero address")); ERC1155Extended.burn(owner, 1, 1); } @@ -1539,7 +1525,7 @@ contract ERC1155Test is Test { vm.stopPrank(); vm.startPrank(firstOwner); - vm.expectRevert(bytes("ERC1155: burn amount exceeds balance")); + vm.expectRevert(bytes("erc1155: burn amount exceeds balance")); ERC1155Extended.burn(firstOwner, id, 16); vm.stopPrank(); } @@ -1547,7 +1533,7 @@ contract ERC1155Test is Test { function testBurnNonExistentTokenId() public { address firstOwner = makeAddr("firstOwner"); vm.prank(firstOwner); - vm.expectRevert(bytes("ERC1155: burn amount exceeds total_supply")); + vm.expectRevert(bytes("erc1155: burn amount exceeds total_supply")); ERC1155Extended.burn(firstOwner, 1, 1); } @@ -1645,7 +1631,7 @@ contract ERC1155Test is Test { vm.startPrank(operator); vm.expectRevert( - bytes("ERC1155: caller is not token owner or approved") + bytes("erc1155: caller is not token owner or approved") ); ERC1155Extended.burn_batch(owner, ids, amounts); vm.stopPrank(); @@ -1674,9 +1660,9 @@ contract ERC1155Test is Test { amounts2[2] = 20; vm.startPrank(owner); - vm.expectRevert(bytes("ERC1155: ids and amounts length mismatch")); + vm.expectRevert(bytes("erc1155: ids and amounts length mismatch")); ERC1155Extended.burn_batch(owner, ids1, amounts1); - vm.expectRevert(bytes("ERC1155: ids and amounts length mismatch")); + vm.expectRevert(bytes("erc1155: ids and amounts length mismatch")); ERC1155Extended.burn_batch(owner, ids2, amounts2); vm.stopPrank(); } @@ -1696,7 +1682,7 @@ contract ERC1155Test is Test { amounts[3] = 20; vm.prank(owner); - vm.expectRevert(bytes("ERC1155: burn from the zero address")); + vm.expectRevert(bytes("erc1155: burn from the zero address")); ERC1155Extended.burn_batch(owner, ids, amounts); } @@ -1720,7 +1706,7 @@ contract ERC1155Test is Test { vm.stopPrank(); vm.startPrank(nonOwner); - vm.expectRevert(bytes("ERC1155: burn amount exceeds balance")); + vm.expectRevert(bytes("erc1155: burn amount exceeds balance")); ERC1155Extended.burn_batch(nonOwner, ids, amounts); vm.stopPrank(); } @@ -1740,7 +1726,7 @@ contract ERC1155Test is Test { amounts[3] = 20; vm.prank(owner); - vm.expectRevert(bytes("ERC1155: burn amount exceeds total_supply")); + vm.expectRevert(bytes("erc1155: burn amount exceeds total_supply")); ERC1155Extended.burn_batch(owner, ids, amounts); } @@ -1889,12 +1875,12 @@ contract ERC1155Test is Test { bytes memory data = new bytes(0); vm.startPrank(deployer); vm.expectRevert( - bytes("ERC1155: transfer to non-ERC1155Receiver implementer") + bytes("erc1155: transfer to non-IERC1155Receiver implementer") ); ERC1155Extended.safe_mint(receiver, id1, amount1, data); vm.expectRevert( - bytes("ERC1155: transfer to non-ERC1155Receiver implementer") + bytes("erc1155: transfer to non-IERC1155Receiver implementer") ); ERC1155Extended.safe_mint(receiver, id2, amount2, data); vm.stopPrank(); @@ -1951,10 +1937,10 @@ contract ERC1155Test is Test { uint256 amount2 = 15; bytes memory data = new bytes(0); vm.startPrank(deployer); - vm.expectRevert(bytes("ERC1155: mint to the zero address")); + vm.expectRevert(bytes("erc1155: mint to the zero address")); ERC1155Extended.safe_mint(receiver, id1, amount1, data); - vm.expectRevert(bytes("ERC1155: mint to the zero address")); + vm.expectRevert(bytes("erc1155: mint to the zero address")); ERC1155Extended.safe_mint(receiver, id2, amount2, data); vm.stopPrank(); } @@ -1967,10 +1953,10 @@ contract ERC1155Test is Test { uint256 amount2 = 15; bytes memory data = new bytes(0); vm.startPrank(makeAddr("nonOwner")); - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc1155: access is denied")); ERC1155Extended.safe_mint(receiver, id1, amount1, data); - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc1155: access is denied")); ERC1155Extended.safe_mint(receiver, id2, amount2, data); vm.stopPrank(); } @@ -2143,7 +2129,7 @@ contract ERC1155Test is Test { vm.startPrank(deployer); vm.expectRevert( - bytes("ERC1155: transfer to non-ERC1155Receiver implementer") + bytes("erc1155: transfer to non-IERC1155Receiver implementer") ); ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data); vm.stopPrank(); @@ -2269,10 +2255,10 @@ contract ERC1155Test is Test { amounts2[2] = 10; vm.startPrank(deployer); - vm.expectRevert("ERC1155: ids and amounts length mismatch"); + vm.expectRevert("erc1155: ids and amounts length mismatch"); ERC1155Extended.safe_mint_batch(deployer, ids1, amounts1, data); - vm.expectRevert("ERC1155: ids and amounts length mismatch"); + vm.expectRevert("erc1155: ids and amounts length mismatch"); ERC1155Extended.safe_mint_batch(deployer, ids2, amounts2, data); vm.stopPrank(); } @@ -2292,7 +2278,7 @@ contract ERC1155Test is Test { amounts[3] = 20; vm.startPrank(deployer); - vm.expectRevert(bytes("ERC1155: mint to the zero address")); + vm.expectRevert(bytes("erc1155: mint to the zero address")); ERC1155Extended.safe_mint_batch(zeroAddress, ids, amounts, data); vm.stopPrank(); } @@ -2312,7 +2298,7 @@ contract ERC1155Test is Test { amounts[3] = 20; vm.startPrank(makeAddr("nonOwner")); - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc1155: access is denied")); ERC1155Extended.safe_mint_batch(makeAddr("owner"), ids, amounts, data); vm.stopPrank(); } @@ -2365,19 +2351,19 @@ contract ERC1155Test is Test { } function testSetMinterNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC1155Extended.set_minter(makeAddr("minter"), true); } function testSetMinterToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("AccessControl: minter is the zero address")); + vm.expectRevert(bytes("erc1155: minter is the zero address")); ERC1155Extended.set_minter(zeroAddress, true); } function testSetMinterRemoveOwnerAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("AccessControl: minter is owner address")); + vm.expectRevert(bytes("erc1155: minter is owner address")); ERC1155Extended.set_minter(deployer, false); } @@ -2403,13 +2389,13 @@ contract ERC1155Test is Test { } function testTransferOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC1155Extended.transfer_ownership(makeAddr("newOwner")); } function testTransferOwnershipToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("Ownable: new owner is the zero address")); + vm.expectRevert(bytes("erc1155: new owner is the zero address")); ERC1155Extended.transfer_ownership(zeroAddress); } @@ -2428,7 +2414,7 @@ contract ERC1155Test is Test { } function testRenounceOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC1155Extended.renounce_ownership(); } @@ -2932,7 +2918,7 @@ contract ERC1155Test is Test { function testFuzzSetUriNonMinter(address nonOwner) public { vm.assume(nonOwner != deployer); - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc1155: access is denied")); vm.prank(nonOwner); ERC1155Extended.set_uri(1, "my_awesome_uri"); } @@ -3284,10 +3270,10 @@ contract ERC1155Test is Test { uint256 amount2 = 15; bytes memory data = new bytes(0); vm.startPrank(nonOwner); - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc1155: access is denied")); ERC1155Extended.safe_mint(receiver, id1, amount1, data); - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc1155: access is denied")); ERC1155Extended.safe_mint(receiver, id2, amount2, data); vm.stopPrank(); } @@ -3460,7 +3446,7 @@ contract ERC1155Test is Test { amounts[3] = 20; vm.startPrank(nonOwner); - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc1155: access is denied")); ERC1155Extended.safe_mint_batch(makeAddr("owner"), ids, amounts, data); vm.stopPrank(); } @@ -3486,7 +3472,7 @@ contract ERC1155Test is Test { string calldata minter ) public { vm.assume(msgSender != deployer); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC1155Extended.set_minter(makeAddr(minter), true); } @@ -3535,7 +3521,7 @@ contract ERC1155Test is Test { ) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC1155Extended.transfer_ownership(newOwner); } @@ -3566,7 +3552,7 @@ contract ERC1155Test is Test { function testFuzzRenounceOwnershipNonOwner(address nonOwner) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC1155Extended.renounce_ownership(); } } @@ -3586,8 +3572,8 @@ contract ERC1155Invariants is Test { bytes memory args = abi.encode(_BASE_URI); ERC1155Extended = IERC1155Extended( vyperDeployer.deployContract( - "src/snekmate/tokens/", - "ERC1155", + "src/snekmate/tokens/mocks/", + "erc1155_mock", args ) ); @@ -3596,7 +3582,7 @@ contract ERC1155Invariants is Test { targetSender(deployer); } - function invariantOwner() public view { + function statefulFuzzOwner() public view { assertEq(ERC1155Extended.owner(), erc1155Handler.owner()); } } diff --git a/test/tokens/ERC20.t.sol b/test/tokens/ERC20.t.sol index d0a4f9de..b8718f69 100644 --- a/test/tokens/ERC20.t.sol +++ b/test/tokens/ERC20.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -11,6 +11,7 @@ import {IERC20Extended} from "./interfaces/IERC20Extended.sol"; contract ERC20Test is Test { string private constant _NAME = "MyToken"; string private constant _SYMBOL = "WAGMI"; + uint8 private constant _DECIMALS = 18; string private constant _NAME_EIP712 = "MyToken"; string private constant _VERSION_EIP712 = "1"; uint256 private constant _INITIAL_SUPPLY = type(uint8).max; @@ -45,12 +46,17 @@ contract ERC20Test is Test { bytes memory args = abi.encode( _NAME, _SYMBOL, + _DECIMALS, _INITIAL_SUPPLY, _NAME_EIP712, _VERSION_EIP712 ); ERC20Extended = IERC20Extended( - vyperDeployer.deployContract("src/snekmate/tokens/", "ERC20", args) + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc20_mock", + args + ) ); ERC20ExtendedAddr = address(ERC20Extended); _CACHED_DOMAIN_SEPARATOR = keccak256( @@ -66,9 +72,9 @@ contract ERC20Test is Test { function testInitialSetup() public { uint256 multiplier = 10 ** uint256(ERC20Extended.decimals()); - assertEq(ERC20Extended.decimals(), 18); assertEq(ERC20Extended.name(), _NAME); assertEq(ERC20Extended.symbol(), _SYMBOL); + assertEq(ERC20Extended.decimals(), _DECIMALS); assertEq(ERC20Extended.totalSupply(), _INITIAL_SUPPLY * multiplier); assertEq( ERC20Extended.balanceOf(deployer), @@ -90,16 +96,21 @@ contract ERC20Test is Test { bytes memory args = abi.encode( _NAME, _SYMBOL, + _DECIMALS, _INITIAL_SUPPLY, _NAME_EIP712, _VERSION_EIP712 ); ERC20ExtendedInitialEvent = IERC20Extended( - vyperDeployer.deployContract("src/snekmate/tokens/", "ERC20", args) + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc20_mock", + args + ) ); - assertEq(ERC20ExtendedInitialEvent.decimals(), 18); assertEq(ERC20ExtendedInitialEvent.name(), _NAME); assertEq(ERC20ExtendedInitialEvent.symbol(), _SYMBOL); + assertEq(ERC20ExtendedInitialEvent.decimals(), _DECIMALS); assertEq( ERC20ExtendedInitialEvent.totalSupply(), _INITIAL_SUPPLY * multiplier @@ -142,7 +153,7 @@ contract ERC20Test is Test { function testTransferInvalidAmount() public { vm.prank(deployer); - vm.expectRevert(bytes("ERC20: transfer amount exceeds balance")); + vm.expectRevert(bytes("erc20: transfer amount exceeds balance")); ERC20Extended.transfer(makeAddr("to"), type(uint256).max); } @@ -165,7 +176,7 @@ contract ERC20Test is Test { address owner = deployer; uint256 amount = ERC20Extended.balanceOf(owner); vm.prank(owner); - vm.expectRevert(bytes("ERC20: transfer to the zero address")); + vm.expectRevert(bytes("erc20: transfer to the zero address")); ERC20Extended.transfer(zeroAddress, amount); } @@ -175,7 +186,7 @@ contract ERC20Test is Test { vm.prank(owner); ERC20Extended.burn(amount); vm.prank(zeroAddress); - vm.expectRevert(bytes("ERC20: transfer from the zero address")); + vm.expectRevert(bytes("erc20: transfer from the zero address")); ERC20Extended.transfer(makeAddr("to"), amount); } @@ -249,13 +260,13 @@ contract ERC20Test is Test { address owner = deployer; uint256 amount = ERC20Extended.balanceOf(owner); vm.prank(owner); - vm.expectRevert(bytes("ERC20: approve to the zero address")); + vm.expectRevert(bytes("erc20: approve to the zero address")); ERC20Extended.approve(zeroAddress, amount); } function testApproveFromZeroAddress() public { vm.prank(zeroAddress); - vm.expectRevert(bytes("ERC20: approve from the zero address")); + vm.expectRevert(bytes("erc20: approve from the zero address")); ERC20Extended.approve(makeAddr("spender"), type(uint256).max); } @@ -290,7 +301,7 @@ contract ERC20Test is Test { vm.prank(owner); ERC20Extended.approve(spender, amount); vm.prank(spender); - vm.expectRevert(bytes("ERC20: transfer amount exceeds balance")); + vm.expectRevert(bytes("erc20: transfer amount exceeds balance")); ERC20Extended.transferFrom(owner, makeAddr("to"), amount); } @@ -301,7 +312,7 @@ contract ERC20Test is Test { vm.prank(owner); ERC20Extended.approve(spender, amount - 1); vm.prank(spender); - vm.expectRevert(bytes("ERC20: insufficient allowance")); + vm.expectRevert(bytes("erc20: insufficient allowance")); ERC20Extended.transferFrom(owner, makeAddr("to"), amount); } @@ -312,7 +323,7 @@ contract ERC20Test is Test { vm.prank(owner); ERC20Extended.approve(spender, amount - 1); vm.prank(spender); - vm.expectRevert(bytes("ERC20: insufficient allowance")); + vm.expectRevert(bytes("erc20: insufficient allowance")); ERC20Extended.transferFrom(owner, makeAddr("to"), amount); } @@ -342,13 +353,13 @@ contract ERC20Test is Test { vm.prank(owner); ERC20Extended.approve(spender, amount); vm.prank(spender); - vm.expectRevert(bytes("ERC20: transfer to the zero address")); + vm.expectRevert(bytes("erc20: transfer to the zero address")); ERC20Extended.transferFrom(owner, zeroAddress, amount); } function testTransferFromFromZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("ERC20: approve from the zero address")); + vm.expectRevert(bytes("erc20: approve from the zero address")); ERC20Extended.transferFrom(zeroAddress, makeAddr("to"), 0); } @@ -385,13 +396,13 @@ contract ERC20Test is Test { uint256 balance = ERC20Extended.balanceOf(owner); uint256 amount = balance + 1; vm.prank(owner); - vm.expectRevert(bytes("ERC20: burn amount exceeds balance")); + vm.expectRevert(bytes("erc20: burn amount exceeds balance")); ERC20Extended.burn(amount); } function testBurnFromZeroAddress() public { vm.prank(zeroAddress); - vm.expectRevert(bytes("ERC20: burn from the zero address")); + vm.expectRevert(bytes("erc20: burn from the zero address")); ERC20Extended.burn(0); } @@ -452,7 +463,7 @@ contract ERC20Test is Test { vm.prank(owner); ERC20Extended.approve(spender, amount); vm.prank(spender); - vm.expectRevert(bytes("ERC20: burn amount exceeds balance")); + vm.expectRevert(bytes("erc20: burn amount exceeds balance")); ERC20Extended.burn_from(owner, amount); } @@ -463,7 +474,7 @@ contract ERC20Test is Test { vm.prank(owner); ERC20Extended.approve(spender, amount - 1); vm.prank(spender); - vm.expectRevert(bytes("ERC20: insufficient allowance")); + vm.expectRevert(bytes("erc20: insufficient allowance")); ERC20Extended.burn_from(owner, amount); } @@ -474,7 +485,7 @@ contract ERC20Test is Test { vm.prank(owner); ERC20Extended.approve(spender, amount - 1); vm.prank(spender); - vm.expectRevert(bytes("ERC20: insufficient allowance")); + vm.expectRevert(bytes("erc20: insufficient allowance")); ERC20Extended.burn_from(owner, amount); } @@ -499,7 +510,7 @@ contract ERC20Test is Test { function testBurnFromFromZeroAddress() public { vm.prank(zeroAddress); - vm.expectRevert(bytes("ERC20: approve to the zero address")); + vm.expectRevert(bytes("erc20: approve to the zero address")); ERC20Extended.burn_from(makeAddr("owner"), 0); } @@ -521,13 +532,13 @@ contract ERC20Test is Test { } function testMintNonMinter() public { - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc20: access is denied")); ERC20Extended.mint(makeAddr("owner"), 100); } function testMintToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("ERC20: mint to the zero address")); + vm.expectRevert(bytes("erc20: mint to the zero address")); ERC20Extended.mint(zeroAddress, 100); } @@ -554,19 +565,19 @@ contract ERC20Test is Test { } function testSetMinterNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC20Extended.set_minter(makeAddr("minter"), true); } function testSetMinterToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("AccessControl: minter is the zero address")); + vm.expectRevert(bytes("erc20: minter is the zero address")); ERC20Extended.set_minter(zeroAddress, true); } function testSetMinterRemoveOwnerAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("AccessControl: minter is owner address")); + vm.expectRevert(bytes("erc20: minter is owner address")); ERC20Extended.set_minter(deployer, false); } @@ -632,7 +643,7 @@ contract ERC20Test is Test { vm.expectEmit(true, true, false, true); emit IERC20.Approval(owner, spender, amount); ERC20Extended.permit(owner, spender, amount, deadline, v, r, s); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC20Extended.permit(owner, spender, amount, deadline, v, r, s); } @@ -662,7 +673,7 @@ contract ERC20Test is Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC20Extended.permit(owner, spender, amount, deadline, v, r, s); } @@ -700,7 +711,7 @@ contract ERC20Test is Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC20Extended.permit(owner, spender, amount, deadline, v, r, s); } @@ -730,7 +741,7 @@ contract ERC20Test is Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC20Extended.permit(owner, spender, amount, deadline, v, r, s); } @@ -760,7 +771,7 @@ contract ERC20Test is Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: expired deadline")); + vm.expectRevert(bytes("erc20: expired deadline")); ERC20Extended.permit(owner, spender, amount, deadline, v, r, s); } @@ -834,13 +845,13 @@ contract ERC20Test is Test { } function testTransferOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC20Extended.transfer_ownership(makeAddr("newOwner")); } function testTransferOwnershipToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("Ownable: new owner is the zero address")); + vm.expectRevert(bytes("erc20: new owner is the zero address")); ERC20Extended.transfer_ownership(zeroAddress); } @@ -859,7 +870,7 @@ contract ERC20Test is Test { } function testRenounceOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC20Extended.renounce_ownership(); } @@ -888,7 +899,7 @@ contract ERC20Test is Test { amount != 0 ); vm.prank(owner); - vm.expectRevert(bytes("ERC20: transfer amount exceeds balance")); + vm.expectRevert(bytes("erc20: transfer amount exceeds balance")); ERC20Extended.transfer(to, amount); } @@ -948,7 +959,7 @@ contract ERC20Test is Test { ERC20Extended.approve(spender, amount); vm.stopPrank(); - vm.expectRevert(bytes("ERC20: insufficient allowance")); + vm.expectRevert(bytes("erc20: insufficient allowance")); ERC20Extended.transferFrom(owner, to, amount + increment); } @@ -970,7 +981,7 @@ contract ERC20Test is Test { function testFuzzBurnInvalidAmount(address owner, uint256 amount) public { vm.assume(owner != deployer && owner != zeroAddress && amount != 0); vm.prank(owner); - vm.expectRevert(bytes("ERC20: burn amount exceeds balance")); + vm.expectRevert(bytes("erc20: burn amount exceeds balance")); ERC20Extended.burn(amount); } @@ -1007,7 +1018,7 @@ contract ERC20Test is Test { ERC20Extended.approve(spender, amount); vm.stopPrank(); - vm.expectRevert(bytes("ERC20: insufficient allowance")); + vm.expectRevert(bytes("erc20: insufficient allowance")); ERC20Extended.burn_from(owner, amount + increment); } @@ -1032,7 +1043,7 @@ contract ERC20Test is Test { string calldata owner, uint256 amount ) public { - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc20: access is denied")); ERC20Extended.mint(makeAddr(owner), amount); } @@ -1057,7 +1068,7 @@ contract ERC20Test is Test { string calldata minter ) public { vm.assume(msgSender != deployer); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC20Extended.set_minter(makeAddr(minter), true); } @@ -1132,7 +1143,7 @@ contract ERC20Test is Test { ) ) ); - vm.expectRevert(bytes("ERC20Permit: invalid signature")); + vm.expectRevert(bytes("erc20: invalid signature")); ERC20Extended.permit(ownerAddr, spenderAddr, amount, deadline, v, r, s); } @@ -1239,7 +1250,7 @@ contract ERC20Test is Test { ) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC20Extended.transfer_ownership(newOwner); } @@ -1270,7 +1281,7 @@ contract ERC20Test is Test { function testFuzzRenounceOwnershipNonOwner(address nonOwner) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC20Extended.renounce_ownership(); } } @@ -1278,6 +1289,7 @@ contract ERC20Test is Test { contract ERC20Invariants is Test { string private constant _NAME = "MyToken"; string private constant _SYMBOL = "WAGMI"; + uint8 private constant _DECIMALS = 18; string private constant _NAME_EIP712 = "MyToken"; string private constant _VERSION_EIP712 = "1"; uint256 private constant _INITIAL_SUPPLY = type(uint8).max; @@ -1294,12 +1306,17 @@ contract ERC20Invariants is Test { bytes memory args = abi.encode( _NAME, _SYMBOL, + _DECIMALS, _INITIAL_SUPPLY, _NAME_EIP712, _VERSION_EIP712 ); ERC20Extended = IERC20Extended( - vyperDeployer.deployContract("src/snekmate/tokens/", "ERC20", args) + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc20_mock", + args + ) ); erc20Handler = new ERC20Handler( ERC20Extended, @@ -1310,11 +1327,11 @@ contract ERC20Invariants is Test { targetSender(deployer); } - function invariantTotalSupply() public view { + function statefulFuzzTotalSupply() public view { assertEq(ERC20Extended.totalSupply(), erc20Handler.totalSupply()); } - function invariantOwner() public view { + function statefulFuzzOwner() public view { assertEq(ERC20Extended.owner(), erc20Handler.owner()); } } diff --git a/test/tokens/ERC721.t.sol b/test/tokens/ERC721.t.sol index 46746891..8ff0ab76 100644 --- a/test/tokens/ERC721.t.sol +++ b/test/tokens/ERC721.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {stdError} from "forge-std/StdError.sol"; @@ -92,7 +92,7 @@ contract ERC721Test is Test { bytes memory data ) internal { vm.startPrank(makeAddr("nonOwner")); - vm.expectRevert(bytes("ERC721: caller is not token owner or approved")); + vm.expectRevert(bytes("erc721: caller is not token owner or approved")); if (!withData) { Address.functionCall( ERC721ExtendedAddr, @@ -118,7 +118,7 @@ contract ERC721Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: transfer from incorrect owner")); + vm.expectRevert(bytes("erc721: transfer from incorrect owner")); if (!withData) { Address.functionCall( ERC721ExtendedAddr, @@ -144,7 +144,7 @@ contract ERC721Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); if (!withData) { Address.functionCall( ERC721ExtendedAddr, @@ -170,7 +170,7 @@ contract ERC721Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: transfer to the zero address")); + vm.expectRevert(bytes("erc721: transfer to the zero address")); if (!withData) { Address.functionCall( ERC721ExtendedAddr, @@ -471,7 +471,7 @@ contract ERC721Test is Test { vm.revertTo(snapshot); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); Address.functionCall( ERC721ExtendedAddr, abi.encodeWithSignature( @@ -494,7 +494,11 @@ contract ERC721Test is Test { _VERSION_EIP712 ); ERC721Extended = IERC721Extended( - vyperDeployer.deployContract("src/snekmate/tokens/", "ERC721", args) + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc721_mock", + args + ) ); ERC721ExtendedAddr = address(ERC721Extended); _CACHED_DOMAIN_SEPARATOR = keccak256( @@ -527,7 +531,11 @@ contract ERC721Test is Test { _VERSION_EIP712 ); ERC721ExtendedInitialEvent = IERC721Extended( - vyperDeployer.deployContract("src/snekmate/tokens/", "ERC721", args) + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc721_mock", + args + ) ); assertEq(ERC721ExtendedInitialEvent.name(), _NAME); assertEq(ERC721ExtendedInitialEvent.symbol(), _SYMBOL); @@ -592,7 +600,7 @@ contract ERC721Test is Test { } function testBalanceOfZeroAddress() public { - vm.expectRevert(bytes("ERC721: the zero address is not a valid owner")); + vm.expectRevert(bytes("erc721: the zero address is not a valid owner")); ERC721Extended.balanceOf(zeroAddress); } @@ -606,7 +614,7 @@ contract ERC721Test is Test { } function testOwnerOfInvalidTokenId() public { - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.ownerOf(0); } @@ -729,7 +737,7 @@ contract ERC721Test is Test { vm.startPrank(owner); vm.expectRevert( - bytes("ERC721: transfer to non-ERC721Receiver implementer") + bytes("erc721: transfer to non-IERC721Receiver implementer") ); ERC721Extended.safeTransferFrom(owner, receiver, 0, new bytes(0)); vm.stopPrank(); @@ -939,7 +947,7 @@ contract ERC721Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: approval to current owner")); + vm.expectRevert(bytes("erc721: approval to current owner")); ERC721Extended.approve(owner, tokenId); vm.stopPrank(); } @@ -955,7 +963,7 @@ contract ERC721Test is Test { vm.startPrank(makeAddr("nonOwner")); vm.expectRevert( bytes( - "ERC721: approve caller is not token owner or approved for all" + "erc721: approve caller is not token owner or approved for all" ) ); ERC721Extended.approve(makeAddr("to"), tokenId); @@ -978,7 +986,7 @@ contract ERC721Test is Test { vm.startPrank(spender); vm.expectRevert( bytes( - "ERC721: approve caller is not token owner or approved for all" + "erc721: approve caller is not token owner or approved for all" ) ); ERC721Extended.approve(makeAddr("to"), tokenId); @@ -1016,7 +1024,7 @@ contract ERC721Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.approve(makeAddr("to"), tokenId + 1); vm.stopPrank(); } @@ -1095,13 +1103,13 @@ contract ERC721Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: approve to caller")); + vm.expectRevert(bytes("erc721: approve to caller")); ERC721Extended.setApprovalForAll(owner, true); vm.stopPrank(); } function testGetApprovedInvalidTokenId() public { - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.getApproved(0); } @@ -1154,7 +1162,11 @@ contract ERC721Test is Test { _VERSION_EIP712 ); ERC721ExtendedNoBaseURI = IERC721Extended( - vyperDeployer.deployContract("src/snekmate/tokens/", "ERC721", args) + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc721_mock", + args + ) ); address owner = makeAddr("owner"); string memory uri = "my_awesome_nft_uri"; @@ -1165,7 +1177,7 @@ contract ERC721Test is Test { } function testTokenURIInvalidTokenId() public { - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.tokenURI(0); } @@ -1180,7 +1192,7 @@ contract ERC721Test is Test { ERC721Extended.burn(0); vm.stopPrank(); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.tokenURI(0); } @@ -1237,7 +1249,7 @@ contract ERC721Test is Test { vm.stopPrank(); assertEq(ERC721Extended.totalSupply(), 2); - vm.expectRevert(bytes("ERC721Enumerable: global index out of bounds")); + vm.expectRevert(bytes("erc721: global index out of bounds")); ERC721Extended.tokenByIndex(2); } @@ -1313,7 +1325,7 @@ contract ERC721Test is Test { ERC721Extended.safe_mint(owner, uri3); vm.stopPrank(); assertEq(ERC721Extended.totalSupply(), 3); - vm.expectRevert(bytes("ERC721Enumerable: owner index out of bounds")); + vm.expectRevert(bytes("erc721: owner index out of bounds")); ERC721Extended.tokenOfOwnerByIndex(owner, tokenId + 3); vm.startPrank(owner); @@ -1322,7 +1334,7 @@ contract ERC721Test is Test { ERC721Extended.safeTransferFrom(owner, other, tokenId + 2, ""); vm.stopPrank(); assertEq(ERC721Extended.totalSupply(), 3); - vm.expectRevert(bytes("ERC721Enumerable: owner index out of bounds")); + vm.expectRevert(bytes("erc721: owner index out of bounds")); ERC721Extended.tokenOfOwnerByIndex(owner, tokenId); assertEq(ERC721Extended.tokenOfOwnerByIndex(other, tokenId), tokenId); assertEq( @@ -1349,11 +1361,11 @@ contract ERC721Test is Test { vm.expectEmit(true, true, true, false); emit IERC721.Transfer(owner, zeroAddress, tokenId); ERC721Extended.burn(tokenId); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.burn(tokenId); vm.stopPrank(); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.ownerOf(tokenId); assertEq(ERC721Extended.balanceOf(owner), 1); } @@ -1371,7 +1383,7 @@ contract ERC721Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.burn(tokenId + 2); ERC721Extended.setApprovalForAll(operator, true); ERC721Extended.approve(other, tokenId + 1); @@ -1390,13 +1402,13 @@ contract ERC721Test is Test { vm.stopPrank(); vm.startPrank(owner); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.burn(tokenId); vm.stopPrank(); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.ownerOf(tokenId); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.getApproved(tokenId); assertEq(ERC721Extended.balanceOf(owner), 0); assertEq(ERC721Extended.balanceOf(operator), 0); @@ -1466,14 +1478,14 @@ contract ERC721Test is Test { /** * @dev To display the default storage layout for a contract - * in Vyper, use `vyper -f layout yourFileName.vy`. + * in Vyper, use `vyper -f layout your_filename.vy`. */ vm.store( ERC721ExtendedAddr, bytes32(uint256(18_446_744_073_709_551_627)), bytes32(0) ); - vm.expectRevert(bytes("ERC721: token already minted")); + vm.expectRevert(bytes("erc721: token already minted")); ERC721Extended.safe_mint(owner, ""); vm.stopPrank(); } @@ -1504,7 +1516,7 @@ contract ERC721Test is Test { string memory uri = "my_awesome_nft_uri"; vm.startPrank(deployer); vm.expectRevert( - bytes("ERC721: transfer to non-ERC721Receiver implementer") + bytes("erc721: transfer to non-IERC721Receiver implementer") ); ERC721Extended.safe_mint(owner, uri); vm.stopPrank(); @@ -1561,20 +1573,20 @@ contract ERC721Test is Test { } function testSafeMintNonMinter() public { - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc721: access is denied")); ERC721Extended.safe_mint(makeAddr("owner"), "my_awesome_nft_uri"); } function testSafeMintToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("ERC721: mint to the zero address")); + vm.expectRevert(bytes("erc721: mint to the zero address")); ERC721Extended.safe_mint(zeroAddress, "my_awesome_nft_uri"); } function testSafeMintOverflow() public { /** * @dev To display the default storage layout for a contract - * in Vyper, use `vyper -f layout yourFileName.vy`. + * in Vyper, use `vyper -f layout your_filename.vy`. */ vm.store( ERC721ExtendedAddr, @@ -1603,19 +1615,19 @@ contract ERC721Test is Test { } function testSetMinterNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC721Extended.set_minter(makeAddr("minter"), true); } function testSetMinterToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("AccessControl: minter is the zero address")); + vm.expectRevert(bytes("erc721: minter is the zero address")); ERC721Extended.set_minter(zeroAddress, true); } function testSetMinterRemoveOwnerAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("AccessControl: minter is owner address")); + vm.expectRevert(bytes("erc721: minter is owner address")); ERC721Extended.set_minter(deployer, false); } @@ -1689,7 +1701,7 @@ contract ERC721Test is Test { vm.expectEmit(true, true, true, false); emit IERC721.Approval(owner, spender, tokenId); ERC721Extended.permit(spender, tokenId, deadline, v, r, s); - vm.expectRevert(bytes("ERC721Permit: invalid signature")); + vm.expectRevert(bytes("erc721: invalid signature")); ERC721Extended.permit(spender, tokenId, deadline, v, r, s); } @@ -1723,7 +1735,7 @@ contract ERC721Test is Test { ) ) ); - vm.expectRevert(bytes("ERC721Permit: invalid signature")); + vm.expectRevert(bytes("erc721: invalid signature")); ERC721Extended.permit(spender, tokenId, deadline, v, r, s); } @@ -1765,7 +1777,7 @@ contract ERC721Test is Test { ) ) ); - vm.expectRevert(bytes("ERC721Permit: invalid signature")); + vm.expectRevert(bytes("erc721: invalid signature")); ERC721Extended.permit(spender, tokenId, deadline, v, r, s); } @@ -1799,7 +1811,7 @@ contract ERC721Test is Test { ) ) ); - vm.expectRevert(bytes("ERC721Permit: invalid signature")); + vm.expectRevert(bytes("erc721: invalid signature")); ERC721Extended.permit(spender, tokenId, deadline, v, r, s); } @@ -1833,7 +1845,7 @@ contract ERC721Test is Test { ) ) ); - vm.expectRevert(bytes("ERC721Permit: expired deadline")); + vm.expectRevert(bytes("erc721: expired deadline")); ERC721Extended.permit(spender, tokenId, deadline, v, r, s); } @@ -1907,13 +1919,13 @@ contract ERC721Test is Test { } function testTransferOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC721Extended.transfer_ownership(makeAddr("newOwner")); } function testTransferOwnershipToZeroAddress() public { vm.prank(deployer); - vm.expectRevert(bytes("Ownable: new owner is the zero address")); + vm.expectRevert(bytes("erc721: new owner is the zero address")); ERC721Extended.transfer_ownership(zeroAddress); } @@ -1932,7 +1944,7 @@ contract ERC721Test is Test { } function testRenounceOwnershipNonOwner() public { - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC721Extended.renounce_ownership(); } @@ -2148,7 +2160,7 @@ contract ERC721Test is Test { vm.startPrank(nonOwner); vm.expectRevert( bytes( - "ERC721: approve caller is not token owner or approved for all" + "erc721: approve caller is not token owner or approved for all" ) ); ERC721Extended.approve(makeAddr("to"), tokenId); @@ -2275,11 +2287,11 @@ contract ERC721Test is Test { vm.expectEmit(true, true, true, false); emit IERC721.Transfer(owner, zeroAddress, tokenId); ERC721Extended.burn(tokenId); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.burn(tokenId); vm.stopPrank(); - vm.expectRevert(bytes("ERC721: invalid token ID")); + vm.expectRevert(bytes("erc721: invalid token ID")); ERC721Extended.ownerOf(tokenId); assertEq(ERC721Extended.balanceOf(owner), 1); } @@ -2304,7 +2316,7 @@ contract ERC721Test is Test { function testFuzzSafeMintNonMinter(address nonOwner) public { vm.assume(nonOwner != deployer); - vm.expectRevert(bytes("AccessControl: access is denied")); + vm.expectRevert(bytes("erc721: access is denied")); ERC721Extended.safe_mint(makeAddr("owner"), "my_awesome_nft_uri"); } @@ -2329,7 +2341,7 @@ contract ERC721Test is Test { string calldata minter ) public { vm.assume(msgSender != deployer); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC721Extended.set_minter(makeAddr(minter), true); } @@ -2412,7 +2424,7 @@ contract ERC721Test is Test { ) ) ); - vm.expectRevert(bytes("ERC721Permit: invalid signature")); + vm.expectRevert(bytes("erc721: invalid signature")); ERC721Extended.permit(spenderAddr, tokenId, deadline, v, r, s); } @@ -2519,7 +2531,7 @@ contract ERC721Test is Test { ) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC721Extended.transfer_ownership(newOwner); } @@ -2550,7 +2562,7 @@ contract ERC721Test is Test { function testFuzzRenounceOwnershipNonOwner(address nonOwner) public { vm.assume(nonOwner != deployer); vm.prank(nonOwner); - vm.expectRevert(bytes("Ownable: caller is not the owner")); + vm.expectRevert(bytes("ownable: caller is not the owner")); ERC721Extended.renounce_ownership(); } } @@ -2579,18 +2591,22 @@ contract ERC721Invariants is Test { _VERSION_EIP712 ); ERC721Extended = IERC721Extended( - vyperDeployer.deployContract("src/snekmate/tokens/", "ERC721", args) + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc721_mock", + args + ) ); erc721Handler = new ERC721Handler(ERC721Extended, deployer); targetContract(address(erc721Handler)); targetSender(deployer); } - function invariantTotalSupply() public view { + function statefulFuzzTotalSupply() public view { assertEq(ERC721Extended.totalSupply(), erc721Handler.totalSupply()); } - function invariantOwner() public view { + function statefulFuzzOwner() public view { assertEq(ERC721Extended.owner(), erc721Handler.owner()); } } diff --git a/test/tokens/echidna/ERC20Properties.sol b/test/tokens/echidna/ERC20Properties.sol new file mode 100644 index 00000000..b03c264f --- /dev/null +++ b/test/tokens/echidna/ERC20Properties.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +import {VyperDeployer} from "utils/VyperDeployer.sol"; + +import {ITokenMock} from "properties/ERC20/external/util/ITokenMock.sol"; + +import {CryticERC20ExternalBasicProperties} from "properties/ERC20/external/properties/ERC20ExternalBasicProperties.sol"; +import {CryticERC20ExternalBurnableProperties} from "properties/ERC20/external/properties/ERC20ExternalBurnableProperties.sol"; +import {CryticERC20ExternalMintableProperties} from "properties/ERC20/external/properties/ERC20ExternalMintableProperties.sol"; + +contract CryticERC20ExternalHarness is + CryticERC20ExternalBasicProperties, + CryticERC20ExternalBurnableProperties, + CryticERC20ExternalMintableProperties +{ + string private constant _NAME = "MyToken"; + string private constant _SYMBOL = "WAGMI"; + uint8 private constant _DECIMALS = 18; + string private constant _NAME_EIP712 = "MyToken"; + string private constant _VERSION_EIP712 = "1"; + uint256 private constant _INITIAL_SUPPLY = type(uint8).max; + + VyperDeployer private vyperDeployer = new VyperDeployer(); + + constructor() { + bytes memory args = abi.encode( + _NAME, + _SYMBOL, + _DECIMALS, + _INITIAL_SUPPLY, + _NAME_EIP712, + _VERSION_EIP712 + ); + /** + * @dev `hevm` does not currently work with the EVM version `cancun`: + * https://github.com/ethereum/hevm/issues/469. For Echidna-based tests, + * we therefore use the EVM version `shanghai`. + */ + token = ITokenMock( + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc20_mock", + args, + "shanghai", + "gas" + ) + ); + } +} diff --git a/test/tokens/echidna/ERC721Properties.sol b/test/tokens/echidna/ERC721Properties.sol new file mode 100644 index 00000000..b8c28b42 --- /dev/null +++ b/test/tokens/echidna/ERC721Properties.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +import {VyperDeployer} from "utils/VyperDeployer.sol"; + +import {IERC721Internal} from "properties/ERC721/util/IERC721Internal.sol"; +import {MockReceiver} from "properties/ERC721/external/util/MockReceiver.sol"; + +import {CryticERC721ExternalBasicProperties} from "properties/ERC721/external/properties/ERC721ExternalBasicProperties.sol"; +import {CryticERC721ExternalBurnableProperties} from "properties/ERC721/external/properties/ERC721ExternalBurnableProperties.sol"; +import {CryticERC721ExternalMintableProperties} from "properties/ERC721/external/properties/ERC721ExternalMintableProperties.sol"; + +contract CryticERC721ExternalHarness is + CryticERC721ExternalBasicProperties, + CryticERC721ExternalBurnableProperties, + CryticERC721ExternalMintableProperties +{ + string private constant _NAME = "MyNFT"; + string private constant _SYMBOL = "WAGMI"; + string private constant _BASE_URI = "https://www.wagmi.xyz/"; + string private constant _NAME_EIP712 = "MyNFT"; + string private constant _VERSION_EIP712 = "1"; + + VyperDeployer private vyperDeployer = new VyperDeployer(); + + constructor() { + bytes memory args = abi.encode( + _NAME, + _SYMBOL, + _BASE_URI, + _NAME_EIP712, + _VERSION_EIP712 + ); + /** + * @dev `hevm` does not currently work with the EVM version `cancun`: + * https://github.com/ethereum/hevm/issues/469. For Echidna-based tests, + * we therefore use the EVM version `shanghai`. + */ + token = IERC721Internal( + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc721_mock", + args, + "shanghai", + "gas" + ) + ); + mockSafeReceiver = new MockReceiver(true); + mockUnsafeReceiver = new MockReceiver(false); + } + + function test_ERC721_external_mintIncreasesSupply( + uint256 amount + ) public override { + amount = clampBetween(amount, 0, 64); + super.test_ERC721_external_mintIncreasesSupply(amount); + } + + function test_ERC721_external_mintCreatesFreshToken( + uint256 amount + ) public override { + amount = clampBetween(amount, 0, 64); + super.test_ERC721_external_mintCreatesFreshToken(amount); + } +} diff --git a/test/tokens/halmos/ERC1155TestHalmos.t.sol b/test/tokens/halmos/ERC1155TestHalmos.t.sol new file mode 100644 index 00000000..11f707b0 --- /dev/null +++ b/test/tokens/halmos/ERC1155TestHalmos.t.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; +import {VyperDeployer} from "utils/VyperDeployer.sol"; + +import {IERC1155} from "openzeppelin/token/ERC1155/IERC1155.sol"; + +import {IERC1155Extended} from "../interfaces/IERC1155Extended.sol"; + +/** + * @dev Sets the timeout (in milliseconds) for solving assertion + * violation conditions; `0` means no timeout. + * @notice Halmos currently does not support the new native `assert` + * cheatcodes in `forge-std` `v1.8.0` and above. + * @custom:halmos --solver-timeout-assertion 0 + */ +contract ERC1155TestHalmos is Test, SymTest { + string private constant _BASE_URI = "https://www.wagmi.xyz/"; + + VyperDeployer private vyperDeployer = new VyperDeployer(); + + IERC1155 private erc1155; + address private token; + address[] private holders; + uint256[] private tokenIds; + uint256[] private amounts; + + function setUp() public { + bytes memory args = abi.encode(_BASE_URI); + /** + * @dev Halmos does not currently work with the latest Vyper jump-table-based + * dispatchers: https://github.com/a16z/halmos/issues/253. For Halmos-based tests, + * we therefore disable the optimiser. Furthermore, Halmos does not currently + * work with the EVM version `cancun`: https://github.com/a16z/halmos/issues/290. + * For Halmos-based tests, we therefore use the EVM version `shanghai`. + */ + erc1155 = IERC1155( + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc1155_mock", + args, + "shanghai", + "none" + ) + ); + + address deployer = address(vyperDeployer); + token = address(erc1155); + holders = new address[](3); + holders[0] = address(0x1337); + holders[1] = address(0x31337); + holders[2] = address(0xbA5eD); + + tokenIds = new uint256[](5); + tokenIds[0] = 0; + tokenIds[1] = 1; + tokenIds[2] = 2; + tokenIds[3] = 3; + tokenIds[4] = 4; + + amounts = new uint256[](5); + amounts[0] = 1; + amounts[1] = 2; + amounts[2] = 10; + amounts[3] = 20; + amounts[4] = 50; + + vm.startPrank(deployer); + for (uint256 i = 0; i < tokenIds.length; i++) { + IERC1155Extended(token)._customMint( + deployer, + tokenIds[i], + amounts[i] + ); + } + erc1155.safeTransferFrom( + deployer, + holders[0], + tokenIds[0], + amounts[0], + new bytes(0) + ); + erc1155.safeTransferFrom( + deployer, + holders[0], + tokenIds[1], + amounts[1], + new bytes(42) + ); + erc1155.safeTransferFrom( + deployer, + holders[1], + tokenIds[2], + amounts[2], + new bytes(96) + ); + erc1155.safeTransferFrom( + deployer, + holders[2], + tokenIds[3], + amounts[3], + new bytes(1_024) + ); + vm.stopPrank(); + + vm.startPrank(holders[0]); + erc1155.setApprovalForAll(holders[2], true); + vm.stopPrank(); + + vm.startPrank(holders[1]); + erc1155.setApprovalForAll(holders[2], true); + vm.stopPrank(); + } + + /** + * @dev Currently commented out due to performance and reverting path issues in Halmos. + */ + // function testHalmosAssertNoBackdoor( + // bytes4 selector, + // address caller, + // address other + // ) public { + // /** + // * @dev Using a single `assume` with conjunctions would result in the creation of + // * multiple paths, negatively impacting performance. + // */ + // vm.assume(caller != other); + // vm.assume(selector != IERC1155Extended._customMint.selector); + // vm.assume(selector != IERC1155Extended.safe_mint.selector); + // vm.assume(selector != IERC1155Extended.safe_mint_batch.selector); + // for (uint256 i = 0; i < holders.length; i++) { + // vm.assume(!erc1155.isApprovedForAll(holders[i], caller)); + // } + + // address[] memory callers; + // address[] memory others; + // for (uint256 i = 0; i < tokenIds.length; i++) { + // callers[i] = caller; + // others[i] = other; + // } + + // uint256[] memory oldBalanceCaller = erc1155.balanceOfBatch( + // callers, + // tokenIds + // ); + // uint256[] memory oldBalanceOther = erc1155.balanceOfBatch( + // others, + // tokenIds + // ); + + // vm.startPrank(caller); + // bool success; + // if (selector == IERC1155.safeTransferFrom.selector) { + // // solhint-disable-next-line avoid-low-level-calls + // (success, ) = token.call( + // abi.encodeWithSelector( + // selector, + // svm.createAddress("from"), + // svm.createAddress("to"), + // svm.createUint256("tokenId"), + // svm.createUint256("amount"), + // svm.createBytes(96, "YOLO") + // ) + // ); + // } else if (selector == IERC1155.safeBatchTransferFrom.selector) { + // uint256[] memory ids = new uint256[](5); + // uint256[] memory values = new uint256[](5); + // for (uint256 i = 0; i < ids.length; i++) { + // ids[i] = svm.createUint256("ids"); + // values[i] = svm.createUint256("values"); + // } + // // solhint-disable-next-line avoid-low-level-calls + // (success, ) = token.call( + // abi.encodeWithSelector( + // selector, + // svm.createAddress("from"), + // svm.createAddress("to"), + // ids, + // values, + // svm.createBytes(96, "YOLO") + // ) + // ); + // } else { + // bytes memory args = svm.createBytes(1_024, "WAGMI"); + // // solhint-disable-next-line avoid-low-level-calls + // (success, ) = address(token).call(abi.encodePacked(selector, args)); + // } + // vm.assume(success); + // vm.stopPrank(); + + // for (uint256 i = 0; i < tokenIds.length; i++) { + // assert( + // erc1155.balanceOf(caller, tokenIds[i]) <= oldBalanceCaller[i] + // ); + // assert(erc1155.balanceOf(other, tokenIds[i]) >= oldBalanceOther[i]); + // } + // } + + function testHalmosSafeTransferFrom( + address caller, + address from, + address to, + address other + ) public { + /** + * @dev Using a single `assume` with conjunctions would result in the creation of + * multiple paths, negatively impacting performance. + */ + vm.assume(other != from); + vm.assume(other != to); + + uint256 oldBalanceFrom = erc1155.balanceOf(from, tokenIds[0]); + uint256 oldBalanceTo = erc1155.balanceOf(to, tokenIds[0]); + uint256 oldBalanceOther = erc1155.balanceOf(other, tokenIds[0]); + bool approved = erc1155.isApprovedForAll(from, caller); + + vm.startPrank(caller); + if (svm.createBool("1337")) { + erc1155.safeTransferFrom( + from, + to, + tokenIds[0], + amounts[0], + svm.createBytes(96, "YOLO") + ); + } else { + erc1155.safeBatchTransferFrom( + from, + to, + tokenIds, + amounts, + svm.createBytes(96, "YOLO") + ); + } + vm.stopPrank(); + + (from == caller) ? assert(!approved) : assert(approved); + + uint256 newBalanceFrom = erc1155.balanceOf(from, tokenIds[0]); + uint256 newBalanceTo = erc1155.balanceOf(to, tokenIds[0]); + uint256 newBalanceOther = erc1155.balanceOf(other, tokenIds[0]); + + if (from != to) { + assert(newBalanceFrom == oldBalanceFrom - amounts[0]); + assert(newBalanceTo == oldBalanceTo + amounts[0]); + } else { + assert(newBalanceFrom == oldBalanceFrom); + assert(newBalanceTo == oldBalanceTo); + } + + assert(newBalanceOther == oldBalanceOther); + } +} diff --git a/test/tokens/halmos/ERC20TestHalmos.t.sol b/test/tokens/halmos/ERC20TestHalmos.t.sol new file mode 100644 index 00000000..5cc2e724 --- /dev/null +++ b/test/tokens/halmos/ERC20TestHalmos.t.sol @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; +import {VyperDeployer} from "utils/VyperDeployer.sol"; + +import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol"; + +/** + * @dev Sets the timeout (in milliseconds) for solving assertion + * violation conditions; `0` means no timeout. + * @notice Halmos currently does not support the new native `assert` + * cheatcodes in `forge-std` `v1.8.0` and above. + * @custom:halmos --solver-timeout-assertion 0 + */ +contract ERC20TestHalmos is Test, SymTest { + string private constant _NAME = "MyToken"; + string private constant _SYMBOL = "WAGMI"; + string private constant _NAME_EIP712 = "MyToken"; + string private constant _VERSION_EIP712 = "1"; + + VyperDeployer private vyperDeployer = new VyperDeployer(); + + IERC20 private erc20; + address private token; + address[] private holders; + + /** + * @dev Sets timeout (in milliseconds) for solving branching + * conditions; `0` means no timeout. + * @custom:halmos --solver-timeout-branching 1000 + */ + function setUpSymbolic(uint256 initialSupply_) public { + uint8 decimals = uint8(svm.createUint(8, "decimals")); + bytes memory args = abi.encode( + _NAME, + _SYMBOL, + decimals, + initialSupply_, + _NAME_EIP712, + _VERSION_EIP712 + ); + /** + * @dev Halmos does not currently work with the latest Vyper jump-table-based + * dispatchers: https://github.com/a16z/halmos/issues/253. For Halmos-based tests, + * we therefore disable the optimiser. Furthermore, Halmos does not currently + * work with the EVM version `cancun`: https://github.com/a16z/halmos/issues/290. + * For Halmos-based tests, we therefore use the EVM version `shanghai`. + */ + erc20 = IERC20( + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc20_mock", + args, + "shanghai", + "none" + ) + ); + + address deployer = address(vyperDeployer); + token = address(erc20); + holders = new address[](3); + holders[0] = address(0x1337); + holders[1] = address(0x31337); + holders[2] = address(0xbA5eD); + + for (uint256 i = 0; i < holders.length; i++) { + address account = holders[i]; + uint256 balance = svm.createUint256("balance"); + vm.assume(balance <= erc20.balanceOf(deployer)); + + vm.startPrank(deployer); + erc20.transfer(account, balance); + vm.stopPrank(); + + for (uint256 j = 0; j < i; j++) { + address other = holders[j]; + uint256 amount = svm.createUint256("amount"); + vm.startPrank(account); + erc20.approve(other, amount); + vm.stopPrank(); + } + } + } + + /** + * @notice Forked and adjusted accordingly from here: + * https://github.com/a16z/halmos/blob/main/examples/tokens/ERC20/test/ERC20Test.sol. + */ + function testHalmosAssertNoBackdoor( + bytes4 selector, + address caller, + address other + ) public { + bytes memory args = svm.createBytes(1_024, "WAGMI"); + vm.assume(other != caller); + + uint256 oldBalanceOther = erc20.balanceOf(other); + uint256 oldAllowance = erc20.allowance(other, caller); + + vm.startPrank(caller); + // solhint-disable-next-line avoid-low-level-calls + (bool success, ) = token.call(abi.encodePacked(selector, args)); + vm.assume(success); + vm.stopPrank(); + + uint256 newBalanceOther = erc20.balanceOf(other); + + if (newBalanceOther < oldBalanceOther) { + assert(oldAllowance >= oldBalanceOther - newBalanceOther); + } + } + + /** + * @notice Forked and adjusted accordingly from here: + * https://github.com/a16z/halmos/blob/main/examples/tokens/ERC20/test/ERC20Test.sol. + */ + function testHalmosTransfer( + address sender, + address receiver, + address other, + uint256 amount + ) public { + /** + * @dev Using a single `assume` with conjunctions would result in the creation of + * multiple paths, negatively impacting performance. + */ + vm.assume(other != sender); + vm.assume(other != receiver); + + uint256 oldBalanceSender = erc20.balanceOf(sender); + uint256 oldBalanceReceiver = erc20.balanceOf(receiver); + uint256 oldBalanceOther = erc20.balanceOf(other); + + vm.startPrank(sender); + erc20.transfer(receiver, amount); + vm.stopPrank(); + + uint256 newBalanceSender = erc20.balanceOf(sender); + uint256 newBalanceReceiver = erc20.balanceOf(receiver); + uint256 newBalanceOther = erc20.balanceOf(other); + + if (sender != receiver) { + assert(newBalanceSender == oldBalanceSender - amount); + assert(newBalanceReceiver == oldBalanceReceiver + amount); + } else { + assert(newBalanceSender == oldBalanceSender); + assert(newBalanceReceiver == oldBalanceReceiver); + } + + assert(newBalanceOther == oldBalanceOther); + } + + /** + * @notice Forked and adjusted accordingly from here: + * https://github.com/a16z/halmos/blob/main/examples/tokens/ERC20/test/ERC20Test.sol. + */ + function testHalmosTransferFrom( + address caller, + address from, + address to, + address other, + uint256 amount + ) public { + /** + * @dev Using a single `assume` with conjunctions would result in the creation of + * multiple paths, negatively impacting performance. + */ + vm.assume(other != from); + vm.assume(other != to); + + uint256 oldBalanceFrom = erc20.balanceOf(from); + uint256 oldBalanceTo = erc20.balanceOf(to); + uint256 oldBalanceOther = erc20.balanceOf(other); + uint256 oldAllowance = erc20.allowance(from, caller); + + vm.startPrank(caller); + erc20.transferFrom(from, to, amount); + vm.stopPrank(); + + uint256 newBalanceFrom = erc20.balanceOf(from); + uint256 newBalanceTo = erc20.balanceOf(to); + uint256 newBalanceOther = erc20.balanceOf(other); + + if (from != to) { + assert(newBalanceFrom == oldBalanceFrom - amount); + assert(newBalanceTo == oldBalanceTo + amount); + assert(oldAllowance >= amount); + assert( + oldAllowance == type(uint256).max || + erc20.allowance(from, caller) == oldAllowance - amount + ); + } else { + assert(newBalanceFrom == oldBalanceFrom); + assert(newBalanceTo == oldBalanceTo); + } + + assert(newBalanceOther == oldBalanceOther); + } +} diff --git a/test/tokens/halmos/ERC721TestHalmos.t.sol b/test/tokens/halmos/ERC721TestHalmos.t.sol new file mode 100644 index 00000000..49a59218 --- /dev/null +++ b/test/tokens/halmos/ERC721TestHalmos.t.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; +import {VyperDeployer} from "utils/VyperDeployer.sol"; + +import {IERC721} from "openzeppelin/token/ERC721/IERC721.sol"; + +import {IERC721Extended} from "../interfaces/IERC721Extended.sol"; + +/** + * @dev Sets the timeout (in milliseconds) for solving assertion + * violation conditions; `0` means no timeout. + * @notice Halmos currently does not support the new native `assert` + * cheatcodes in `forge-std` `v1.8.0` and above. + * @custom:halmos --solver-timeout-assertion 0 + */ +contract ERC721TestHalmos is Test, SymTest { + string private constant _NAME = "MyNFT"; + string private constant _SYMBOL = "WAGMI"; + string private constant _BASE_URI = "https://www.wagmi.xyz/"; + string private constant _NAME_EIP712 = "MyNFT"; + string private constant _VERSION_EIP712 = "1"; + + VyperDeployer private vyperDeployer = new VyperDeployer(); + + IERC721 private erc721; + address private token; + address[] private holders; + uint256[] private tokenIds; + + /** + * @dev Sets timeout (in milliseconds) for solving branching + * conditions; `0` means no timeout. + * @custom:halmos --solver-timeout-branching 1000 + */ + function setUp() public { + bytes memory args = abi.encode( + _NAME, + _SYMBOL, + _BASE_URI, + _NAME_EIP712, + _VERSION_EIP712 + ); + /** + * @dev Halmos does not currently work with the latest Vyper jump-table-based + * dispatchers: https://github.com/a16z/halmos/issues/253. For Halmos-based tests, + * we therefore disable the optimiser. Furthermore, Halmos does not currently + * work with the EVM version `cancun`: https://github.com/a16z/halmos/issues/290. + * For Halmos-based tests, we therefore use the EVM version `shanghai`. + */ + erc721 = IERC721( + vyperDeployer.deployContract( + "src/snekmate/tokens/mocks/", + "erc721_mock", + args, + "shanghai", + "none" + ) + ); + + address deployer = address(vyperDeployer); + token = address(erc721); + holders = new address[](3); + holders[0] = address(0x1337); + holders[1] = address(0x31337); + holders[2] = address(0xbA5eD); + + tokenIds = new uint256[](5); + tokenIds[0] = 0; + tokenIds[1] = 1; + tokenIds[2] = 2; + tokenIds[3] = 3; + tokenIds[4] = 4; + + vm.startPrank(deployer); + for (uint256 i = 0; i < tokenIds.length; i++) { + IERC721Extended(token)._customMint(deployer, i); + } + erc721.transferFrom(deployer, holders[0], tokenIds[0]); + erc721.transferFrom(deployer, holders[0], tokenIds[1]); + erc721.transferFrom(deployer, holders[1], tokenIds[2]); + erc721.transferFrom(deployer, holders[2], tokenIds[3]); + vm.stopPrank(); + + vm.startPrank(holders[0]); + erc721.approve(holders[2], tokenIds[0]); + vm.stopPrank(); + + vm.startPrank(holders[1]); + erc721.setApprovalForAll(holders[2], true); + vm.stopPrank(); + } + + /** + * @dev Currently commented out due to performance and reverting path issues in Halmos. + * @notice Forked and adjusted accordingly from here: + * https://github.com/a16z/halmos/blob/main/examples/tokens/ERC721/test/ERC721Test.sol. + */ + // function testHalmosAssertNoBackdoor( + // bytes4 selector, + // address caller, + // address other + // ) public { + // /** + // * @dev Using a single `assume` with conjunctions would result in the creation of + // * multiple paths, negatively impacting performance. + // */ + // vm.assume(caller != other); + // vm.assume(selector != IERC721Extended._customMint.selector); + // vm.assume(selector != IERC721Extended.safe_mint.selector); + // for (uint256 i = 0; i < holders.length; i++) { + // vm.assume(!erc721.isApprovedForAll(holders[i], caller)); + // } + // for (uint256 i = 0; i < tokenIds.length; i++) { + // vm.assume(erc721.getApproved(tokenIds[i]) != caller); + // } + + // uint256 oldBalanceCaller = erc721.balanceOf(caller); + // uint256 oldBalanceOther = erc721.balanceOf(other); + + // vm.startPrank(caller); + // bool success; + // if ( + // selector == + // bytes4(keccak256("safeTransferFrom(address,address,uint256,bytes)")) + // ) { + // // solhint-disable-next-line avoid-low-level-calls + // (success, ) = token.call( + // abi.encodeWithSelector( + // selector, + // svm.createAddress("from"), + // svm.createAddress("to"), + // svm.createUint256("tokenId"), + // svm.createBytes(96, "YOLO") + // ) + // ); + // } else { + // bytes memory args = svm.createBytes(1_024, "WAGMI"); + // // solhint-disable-next-line avoid-low-level-calls + // (success, ) = address(token).call(abi.encodePacked(selector, args)); + // } + // vm.assume(success); + // vm.stopPrank(); + + // uint256 newBalanceCaller = erc721.balanceOf(caller); + // uint256 newBalanceOther = erc721.balanceOf(other); + + // assert(newBalanceCaller <= oldBalanceCaller); + // assert(newBalanceOther >= oldBalanceOther); + // } + + /** + * @notice Forked and adjusted accordingly from here: + * https://github.com/a16z/halmos/blob/main/examples/tokens/ERC721/test/ERC721Test.sol. + */ + function testHalmosSafeTransferFrom( + address caller, + address from, + address to, + address other, + uint256 tokenId, + uint256 otherTokenId + ) public { + /** + * @dev Using a single `assume` with conjunctions would result in the creation of + * multiple paths, negatively impacting performance. + */ + vm.assume(other != from); + vm.assume(other != to); + vm.assume(otherTokenId != tokenId); + + uint256 oldBalanceFrom = erc721.balanceOf(from); + uint256 oldBalanceTo = erc721.balanceOf(to); + uint256 oldBalanceOther = erc721.balanceOf(other); + + address oldOwner = erc721.ownerOf(tokenId); + address oldOtherTokenOwner = erc721.ownerOf(otherTokenId); + bool approved = (caller == oldOwner || + erc721.isApprovedForAll(oldOwner, caller) || + erc721.getApproved(tokenId) == caller); + + vm.startPrank(caller); + if (svm.createBool("1337")) { + erc721.transferFrom(from, to, tokenId); + } else { + erc721.safeTransferFrom( + from, + to, + tokenId, + svm.createBytes(96, "YOLO") + ); + } + vm.stopPrank(); + + assert(from == oldOwner); + assert(approved); + assert(erc721.ownerOf(tokenId) == to); + assert(erc721.getApproved(tokenId) == address(0)); + assert(erc721.ownerOf(otherTokenId) == oldOtherTokenOwner); + + uint256 newBalanceFrom = erc721.balanceOf(from); + uint256 newBalanceTo = erc721.balanceOf(to); + uint256 newBalanceOther = erc721.balanceOf(other); + + if (from != to) { + assert(newBalanceFrom == oldBalanceFrom - 1); + assert(newBalanceTo == oldBalanceTo + 1); + } else { + assert(newBalanceFrom == oldBalanceFrom); + assert(newBalanceTo == oldBalanceTo); + } + + assert(newBalanceOther == oldBalanceOther); + } +} diff --git a/test/tokens/interfaces/IERC1155Extended.sol b/test/tokens/interfaces/IERC1155Extended.sol index 806de8fd..bfe8adcd 100644 --- a/test/tokens/interfaces/IERC1155Extended.sol +++ b/test/tokens/interfaces/IERC1155Extended.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC1155MetadataURI} from "openzeppelin/token/ERC1155/extensions/IERC1155MetadataURI.sol"; @@ -34,6 +34,8 @@ interface IERC1155Extended is IERC1155MetadataURI { bytes calldata data ) external; + function _customMint(address owner, uint256 id, uint256 amount) external; + function safe_mint_batch( address owner, uint256[] calldata ids, diff --git a/test/tokens/interfaces/IERC20Extended.sol b/test/tokens/interfaces/IERC20Extended.sol index 65fae770..cadbd417 100644 --- a/test/tokens/interfaces/IERC20Extended.sol +++ b/test/tokens/interfaces/IERC20Extended.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC20Metadata} from "openzeppelin/token/ERC20/extensions/IERC20Metadata.sol"; import {IERC20Permit} from "openzeppelin/token/ERC20/extensions/IERC20Permit.sol"; diff --git a/test/tokens/interfaces/IERC4494.sol b/test/tokens/interfaces/IERC4494.sol index 1c6f73f1..0b71df54 100644 --- a/test/tokens/interfaces/IERC4494.sol +++ b/test/tokens/interfaces/IERC4494.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC165} from "openzeppelin/utils/introspection/IERC165.sol"; diff --git a/test/tokens/interfaces/IERC721Extended.sol b/test/tokens/interfaces/IERC721Extended.sol index 61c63db0..fef83531 100644 --- a/test/tokens/interfaces/IERC721Extended.sol +++ b/test/tokens/interfaces/IERC721Extended.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC721Metadata} from "openzeppelin/token/ERC721/extensions/IERC721Metadata.sol"; import {IERC721Enumerable} from "openzeppelin/token/ERC721/extensions/IERC721Enumerable.sol"; @@ -27,6 +27,8 @@ interface IERC721Extended is function safe_mint(address owner, string calldata uri) external; + function _customMint(address owner, uint256 amount) external; + function set_minter(address minter, bool status) external; function owner() external view returns (address); diff --git a/test/tokens/mocks/ERC1155ReceiverMock.sol b/test/tokens/mocks/ERC1155ReceiverMock.sol index 67fbc072..f9d85da5 100644 --- a/test/tokens/mocks/ERC1155ReceiverMock.sol +++ b/test/tokens/mocks/ERC1155ReceiverMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {ERC165} from "openzeppelin/utils/introspection/ERC165.sol"; import {IERC1155Receiver} from "openzeppelin/token/ERC1155/IERC1155Receiver.sol"; @@ -13,10 +13,10 @@ import {IERC1155Receiver} from "openzeppelin/token/ERC1155/IERC1155Receiver.sol" * @notice Allows to test receiving ERC-1155 tokens as a smart contract. */ contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { - bytes4 private recRetval; - bool private recReverts; - bytes4 private batRetval; - bool private batReverts; + bytes4 private _recRetval; + bool private _recReverts; + bytes4 private _batRetval; + bool private _batReverts; event Received( address indexed operator, @@ -40,10 +40,10 @@ contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { bytes4 batRetval_, bool batReverts_ ) { - recRetval = recRetval_; - recReverts = recReverts_; - batRetval = batRetval_; - batReverts = batReverts_; + _recRetval = recRetval_; + _recReverts = recReverts_; + _batRetval = batRetval_; + _batReverts = batReverts_; } /** @@ -67,9 +67,9 @@ contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { bytes memory data ) external returns (bytes4) { // solhint-disable-next-line reason-string, gas-custom-errors - require(!recReverts, "ERC1155ReceiverMock: reverting on receive"); + require(!_recReverts, "ERC1155ReceiverMock: reverting on receive"); emit Received(operator, from, id, amount, data); - return recRetval; + return _recRetval; } /** @@ -93,8 +93,11 @@ contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { bytes memory data ) external returns (bytes4) { // solhint-disable-next-line reason-string, gas-custom-errors - require(!batReverts, "ERC1155ReceiverMock: reverting on batch receive"); + require( + !_batReverts, + "ERC1155ReceiverMock: reverting on batch receive" + ); emit BatchReceived(operator, from, ids, amounts, data); - return batRetval; + return _batRetval; } } diff --git a/test/tokens/mocks/ERC721ReceiverMock.sol b/test/tokens/mocks/ERC721ReceiverMock.sol index 2174da47..d44f5c36 100644 --- a/test/tokens/mocks/ERC721ReceiverMock.sol +++ b/test/tokens/mocks/ERC721ReceiverMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC721Receiver} from "openzeppelin/token/ERC721/IERC721Receiver.sol"; diff --git a/test/utils/Base64.t.sol b/test/utils/Base64.t.sol index 7a45f28b..3f5966af 100644 --- a/test/utils/Base64.t.sol +++ b/test/utils/Base64.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {PRBTest} from "prb/test/PRBTest.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -21,7 +21,10 @@ contract Base64Test is PRBTest { function setUp() public { base64 = IBase64( - vyperDeployer.deployContract("src/snekmate/utils/", "Base64") + vyperDeployer.deployContract( + "src/snekmate/utils/mocks/", + "base64_mock" + ) ); } @@ -184,8 +187,8 @@ contract Base64Test is PRBTest { } function testDecodeSentence() public { - string memory text = "Snakes are great animals!"; - string memory data = "U25ha2VzIGFyZSBncmVhdCBhbmltYWxzIQ=="; + string memory text = "Long Live Vyper!"; + string memory data = "TG9uZyBMaXZlIFZ5cGVyIQ=="; bytes[] memory outputStd = base64.decode(data, false); bytes[] memory outputUrl = base64.decode(data, true); bytes memory returnDataStd = bytes.concat( @@ -194,10 +197,7 @@ contract Base64Test is PRBTest { outputStd[2], outputStd[3], outputStd[4], - outputStd[5], - outputStd[6], - outputStd[7], - outputStd[8] + outputStd[5] ); bytes memory returnDataUrl = bytes.concat( outputUrl[0], @@ -205,10 +205,7 @@ contract Base64Test is PRBTest { outputUrl[2], outputUrl[3], outputUrl[4], - outputUrl[5], - outputUrl[6], - outputUrl[7], - outputUrl[8] + outputUrl[5] ); /** * @dev We remove the two trailing zero bytes that stem from @@ -227,7 +224,7 @@ contract Base64Test is PRBTest { function testDecodeSafeUrl() public { string memory text = "[]c!~?[]~"; string memory data = "W11jIX4_W11-"; - vm.expectRevert(bytes("Base64: invalid string")); + vm.expectRevert(bytes("base64: invalid string")); base64.decode(data, false); bytes[] memory outputUrl = base64.decode(data, true); bytes memory returnDataUrl = bytes.concat( @@ -240,9 +237,9 @@ contract Base64Test is PRBTest { function testDataLengthMismatch() public { string memory data = "W11jI"; - vm.expectRevert(bytes("Base64: length mismatch")); + vm.expectRevert(bytes("base64: length mismatch")); base64.decode(data, false); - vm.expectRevert(bytes("Base64: length mismatch")); + vm.expectRevert(bytes("base64: length mismatch")); base64.decode(data, true); } } diff --git a/test/utils/BatchDistributor.t.sol b/test/utils/BatchDistributor.t.sol index 554033f3..d7bc8f49 100644 --- a/test/utils/BatchDistributor.t.sol +++ b/test/utils/BatchDistributor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -7,6 +7,7 @@ import {VyperDeployer} from "utils/VyperDeployer.sol"; import {IERC20Errors} from "openzeppelin/interfaces/draft-IERC6093.sol"; import {ERC20Mock} from "./mocks/ERC20Mock.sol"; +import {DistributeEtherReentrancyMock, DistributeTokenReentrancyMock} from "./mocks/ReentrancyMocks.sol"; import {IBatchDistributor} from "./interfaces/IBatchDistributor.sol"; @@ -21,8 +22,8 @@ contract BatchDistributorTest is Test { function setUp() public { batchDistributor = IBatchDistributor( vyperDeployer.deployContract( - "src/snekmate/utils/", - "BatchDistributor" + "src/snekmate/utils/mocks/", + "batch_distributor_mock" ) ); batchDistributorAddr = address(batchDistributor); @@ -207,6 +208,48 @@ contract BatchDistributorTest is Test { assertEq(batchDistributorAddr.balance, 0); } + function testDistributeEtherReentrancy() public { + /** + * @dev Single-function reentrancy case. + */ + DistributeEtherReentrancyMock distributeEtherReentrancyMock = new DistributeEtherReentrancyMock(); + address alice = address(distributeEtherReentrancyMock); + IBatchDistributor.Transaction[] + memory transaction1 = new IBatchDistributor.Transaction[](1); + transaction1[0] = IBatchDistributor.Transaction({ + recipient: alice, + amount: 2 wei + }); + IBatchDistributor.Batch memory batch1 = IBatchDistributor.Batch({ + txns: transaction1 + }); + + vm.expectRevert( + bytes("DistributeEtherReentrancyMock: reentrancy unsuccessful") + ); + batchDistributor.distribute_ether{value: 2 wei}(batch1); + + /** + * @dev Cross-function reentrancy case. + */ + DistributeTokenReentrancyMock distributeTokenReentrancyMock = new DistributeTokenReentrancyMock(); + address bob = address(distributeTokenReentrancyMock); + IBatchDistributor.Transaction[] + memory transaction2 = new IBatchDistributor.Transaction[](1); + transaction2[0] = IBatchDistributor.Transaction({ + recipient: bob, + amount: 2 wei + }); + IBatchDistributor.Batch memory batch2 = IBatchDistributor.Batch({ + txns: transaction2 + }); + + vm.expectRevert( + bytes("DistributeTokenReentrancyMock: reentrancy unsuccessful") + ); + batchDistributor.distribute_ether{value: 2 wei}(batch2); + } + function testDistributeTokenOneAddressSuccess() public { string memory arg1 = "MyToken"; string memory arg2 = "MTKN"; @@ -444,8 +487,8 @@ contract BatchDistributorInvariants is Test { function setUp() public { batchDistributor = IBatchDistributor( vyperDeployer.deployContract( - "src/snekmate/utils/", - "BatchDistributor" + "src/snekmate/utils/mocks/", + "batch_distributor_mock" ) ); batchDistributorAddr = address(batchDistributor); @@ -464,11 +507,11 @@ contract BatchDistributorInvariants is Test { targetSender(msgSender); } - function invariantNoEtherBalance() public view { + function statefulFuzzNoEtherBalance() public view { assertEq(batchDistributorAddr.balance, 0); } - function invariantNoTokenBalance() public view { + function statefulFuzzNoTokenBalance() public view { /** * @dev This invariant breaks when tokens are sent directly to `batchDistributor` * as part of `distribute_token`. However, this behaviour is acceptable. diff --git a/test/utils/Create2Address.t.sol b/test/utils/Create2Address.t.sol index c9b7dbdd..26a74932 100644 --- a/test/utils/Create2Address.t.sol +++ b/test/utils/Create2Address.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -20,8 +20,8 @@ contract Create2AddressTest is Test { function setUp() public { create2Address = ICreate2Address( vyperDeployer.deployContract( - "src/snekmate/utils/", - "Create2Address" + "src/snekmate/utils/mocks/", + "create2_address_mock" ) ); create2AddressAddr = address(create2Address); diff --git a/test/utils/CreateAddress.t.sol b/test/utils/CreateAddress.t.sol index e3b64447..d2cec417 100644 --- a/test/utils/CreateAddress.t.sol +++ b/test/utils/CreateAddress.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -21,20 +21,23 @@ contract CreateAddressTest is Test { function setUp() public { createAddress = ICreateAddress( - vyperDeployer.deployContract("src/snekmate/utils/", "CreateAddress") + vyperDeployer.deployContract( + "src/snekmate/utils/mocks/", + "create_address_mock" + ) ); createAddressAddr = address(createAddress); } function testComputeAddressRevertTooHighNonce() public { uint72 nonce = uint72(type(uint64).max); - vm.expectRevert(bytes("RLP: invalid nonce value")); + vm.expectRevert(bytes("create_address: invalid nonce value")); createAddress.compute_address_rlp(makeAddr("alice"), nonce); } function testComputeAddressSelfRevertTooHighNonce() public { uint72 nonce = uint72(type(uint64).max); - vm.expectRevert(bytes("RLP: invalid nonce value")); + vm.expectRevert(bytes("create_address: invalid nonce value")); createAddress.compute_address_rlp_self(nonce); } @@ -485,7 +488,7 @@ contract CreateAddressTest is Test { uint256(type(uint64).max), uint256(type(uint256).max) ); - vm.expectRevert(bytes("RLP: invalid nonce value")); + vm.expectRevert(bytes("create_address: invalid nonce value")); createAddress.compute_address_rlp(deployer, nonce); } @@ -497,7 +500,7 @@ contract CreateAddressTest is Test { uint256(type(uint64).max), uint256(type(uint256).max) ); - vm.expectRevert(bytes("RLP: invalid nonce value")); + vm.expectRevert(bytes("create_address: invalid nonce value")); createAddress.compute_address_rlp_self(nonce); } diff --git a/test/utils/ECDSA.t.sol b/test/utils/ECDSA.t.sol index 111d2855..677fcd31 100644 --- a/test/utils/ECDSA.t.sol +++ b/test/utils/ECDSA.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -23,6 +23,9 @@ error InvalidSignatureSValue(address emitter); contract ECDSATest is Test { using BytesLib for bytes; + uint256 private constant _MALLEABILITY_THRESHOLD = + 57_896_044_618_658_097_711_785_492_504_343_953_926_418_782_139_537_452_191_302_581_570_759_080_747_168; + VyperDeployer private vyperDeployer = new VyperDeployer(); // solhint-disable-next-line var-name-mixedcase @@ -30,8 +33,6 @@ contract ECDSATest is Test { address private self = address(this); address private zeroAddress = address(0); - // solhint-disable-next-line var-name-mixedcase - address private ECDSAAddr; /** * @dev Transforms a standard signature into an EIP-2098 @@ -52,9 +53,11 @@ contract ECDSATest is Test { function setUp() public { ECDSA = IECDSA( - vyperDeployer.deployContract("src/snekmate/utils/", "ECDSA") + vyperDeployer.deployContract( + "src/snekmate/utils/mocks/", + "ecdsa_mock" + ) ); - ECDSAAddr = address(ECDSA); } function testRecoverWithValidSignature() public { @@ -155,7 +158,7 @@ contract ECDSATest is Test { bytes32 hash = keccak256("WAGMI"); (, bytes32 r, bytes32 s) = vm.sign(key, hash); bytes memory signatureInvalid = abi.encodePacked(r, s, bytes1(0xa0)); - vm.expectRevert(bytes("ECDSA: invalid signature")); + vm.expectRevert(bytes("ecdsa: invalid signature")); ECDSA.recover_sig(hash, signatureInvalid); } @@ -168,7 +171,7 @@ contract ECDSATest is Test { (, bytes32 r, bytes32 s) = vm.sign(key, hash); bytes memory signatureWithoutVersion = abi.encodePacked(r, s); bytes1 version = 0x00; - vm.expectRevert(bytes("ECDSA: invalid signature")); + vm.expectRevert(bytes("ecdsa: invalid signature")); ECDSA.recover_sig( hash, abi.encodePacked(signatureWithoutVersion, version) @@ -184,7 +187,7 @@ contract ECDSATest is Test { (, bytes32 r, bytes32 s) = vm.sign(key, hash); bytes memory signatureWithoutVersion = abi.encodePacked(r, s); bytes1 version = 0x02; - vm.expectRevert(bytes("ECDSA: invalid signature")); + vm.expectRevert(bytes("ecdsa: invalid signature")); ECDSA.recover_sig( hash, abi.encodePacked(signatureWithoutVersion, version) @@ -223,10 +226,9 @@ contract ECDSATest is Test { (, uint256 key) = makeAddrAndKey("alice"); bytes32 hash = keccak256("WAGMI"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash); - uint256 sTooHigh = uint256(s) + - 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0; + uint256 sTooHigh = uint256(s) + _MALLEABILITY_THRESHOLD; bytes memory signature = abi.encodePacked(r, bytes32(sTooHigh), v); - vm.expectRevert(bytes("ECDSA: invalid signature `s` value")); + vm.expectRevert(bytes("ecdsa: invalid signature `s` value")); ECDSA.recover_sig(hash, signature); /** @@ -238,47 +240,6 @@ contract ECDSATest is Test { to2098Format(signature); } - function testEthSignedMessageHash() public view { - bytes32 hash = keccak256("WAGMI"); - bytes32 digest1 = ECDSA.to_eth_signed_message_hash(hash); - bytes32 digest2 = keccak256( - abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) - ); - assertEq(digest1, digest2); - } - - function testToTypedDataHash() public view { - bytes32 domainSeparator = keccak256("WAGMI"); - bytes32 structHash = keccak256("GM"); - bytes32 digest1 = ECDSA.to_typed_data_hash(domainSeparator, structHash); - bytes32 digest2 = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - assertEq(digest1, digest2); - } - - function testToDataWithIntendedValidatorHash() public { - address validator = makeAddr("intendedValidator"); - bytes memory data = new bytes(42); - bytes32 digest1 = ECDSA.to_data_with_intended_validator_hash( - validator, - data - ); - bytes32 digest2 = keccak256( - abi.encodePacked("\x19\x00", validator, data) - ); - assertEq(digest1, digest2); - } - - function testToDataWithIntendedValidatorHashSelf() public view { - bytes memory data = new bytes(42); - bytes32 digest1 = ECDSA.to_data_with_intended_validator_hash_self(data); - bytes32 digest2 = keccak256( - abi.encodePacked("\x19\x00", ECDSAAddr, data) - ); - assertEq(digest1, digest2); - } - function testFuzzRecoverWithValidSignature( string calldata signer, string calldata message @@ -362,50 +323,4 @@ contract ECDSATest is Test { ); to2098Format(signature); } - - function testFuzzEthSignedMessageHash(string calldata message) public view { - bytes32 hash = keccak256(abi.encode(message)); - bytes32 digest1 = ECDSA.to_eth_signed_message_hash(hash); - bytes32 digest2 = keccak256( - abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) - ); - assertEq(digest1, digest2); - } - - function testFuzzToTypedDataHash( - string calldata domainSeparatorPlain, - string calldata structPlain - ) public view { - bytes32 domainSeparator = keccak256(abi.encode(domainSeparatorPlain)); - bytes32 structHash = keccak256(abi.encode(structPlain)); - bytes32 digest1 = ECDSA.to_typed_data_hash(domainSeparator, structHash); - bytes32 digest2 = keccak256( - abi.encodePacked("\x19\x01", domainSeparator, structHash) - ); - assertEq(digest1, digest2); - } - - function testFuzzToDataWithIntendedValidatorHash( - address validator, - bytes calldata data - ) public view { - bytes32 digest1 = ECDSA.to_data_with_intended_validator_hash( - validator, - data - ); - bytes32 digest2 = keccak256( - abi.encodePacked("\x19\x00", validator, data) - ); - assertEq(digest1, digest2); - } - - function testFuzzToDataWithIntendedValidatorHashSelf( - bytes calldata data - ) public view { - bytes32 digest1 = ECDSA.to_data_with_intended_validator_hash_self(data); - bytes32 digest2 = keccak256( - abi.encodePacked("\x19\x00", ECDSAAddr, data) - ); - assertEq(digest1, digest2); - } } diff --git a/test/utils/EIP712DomainSeparator.t.sol b/test/utils/EIP712DomainSeparator.t.sol index 32526f1d..31263a45 100644 --- a/test/utils/EIP712DomainSeparator.t.sol +++ b/test/utils/EIP712DomainSeparator.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -36,8 +36,8 @@ contract EIP712DomainSeparatorTest is Test { bytes memory args = abi.encode(_NAME, _VERSION); EIP712domainSeparator = IEIP712DomainSeparator( vyperDeployer.deployContract( - "src/snekmate/utils/", - "EIP712DomainSeparator", + "src/snekmate/utils/mocks/", + "eip712_domain_separator_mock", args ) ); diff --git a/test/utils/Math.t.sol b/test/utils/Math.t.sol index 05f07280..bf37cc1c 100644 --- a/test/utils/Math.t.sol +++ b/test/utils/Math.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -29,7 +29,7 @@ contract MathTest is Test { uint256 denominator ) internal pure returns (uint256 result) { // solhint-disable-next-line no-inline-assembly - assembly { + assembly ("memory-safe") { result := mulmod(x, y, denominator) } } @@ -111,7 +111,10 @@ contract MathTest is Test { function setUp() public { math = IMath( - vyperDeployer.deployContract("src/snekmate/utils/", "Math") + vyperDeployer.deployContract( + "src/snekmate/utils/mocks/", + "math_mock" + ) ); } @@ -152,7 +155,7 @@ contract MathTest is Test { assertEq(math.ceil_div(123, 17), 8); assertEq(math.ceil_div(type(uint256).max, 2), 1 << 255); assertEq(math.ceil_div(type(uint256).max, 1), type(uint256).max); - vm.expectRevert(bytes("Math: ceil_div division by zero")); + vm.expectRevert(bytes("math: ceil_div division by zero")); math.ceil_div(1, 0); } @@ -169,16 +172,16 @@ contract MathTest is Test { } function testMulDivDivisionByZero() public { - vm.expectRevert(bytes("Math: mul_div division by zero")); + vm.expectRevert(bytes("math: mul_div division by zero")); math.mul_div(1, 1, 0, false); - vm.expectRevert(bytes("Math: mul_div division by zero")); + vm.expectRevert(bytes("math: mul_div division by zero")); math.mul_div(1, 1, 0, true); } function testMulDivOverflow() public { - vm.expectRevert(bytes("Math: mul_div overflow")); + vm.expectRevert(bytes("math: mul_div overflow")); math.mul_div(type(uint256).max, type(uint256).max, 1, false); - vm.expectRevert(bytes("Math: mul_div overflow")); + vm.expectRevert(bytes("math: mul_div overflow")); math.mul_div(type(uint256).max, type(uint256).max, 1, true); } @@ -234,89 +237,89 @@ contract MathTest is Test { } function testLog2RoundDown() public view { - assertEq(math.log_2(0, false), 0); - assertEq(math.log_2(1, false), 0); - assertEq(math.log_2(2, false), 1); - assertEq(math.log_2(3, false), 1); - assertEq(math.log_2(4, false), 2); - assertEq(math.log_2(5, false), 2); - assertEq(math.log_2(6, false), 2); - assertEq(math.log_2(7, false), 2); - assertEq(math.log_2(8, false), 3); - assertEq(math.log_2(9, false), 3); - assertEq(math.log_2(type(uint256).max, false), 255); + assertEq(math.log2(0, false), 0); + assertEq(math.log2(1, false), 0); + assertEq(math.log2(2, false), 1); + assertEq(math.log2(3, false), 1); + assertEq(math.log2(4, false), 2); + assertEq(math.log2(5, false), 2); + assertEq(math.log2(6, false), 2); + assertEq(math.log2(7, false), 2); + assertEq(math.log2(8, false), 3); + assertEq(math.log2(9, false), 3); + assertEq(math.log2(type(uint256).max, false), 255); } function testLog2RoundUp() public view { - assertEq(math.log_2(0, true), 0); - assertEq(math.log_2(1, true), 0); - assertEq(math.log_2(2, true), 1); - assertEq(math.log_2(3, true), 2); - assertEq(math.log_2(4, true), 2); - assertEq(math.log_2(5, true), 3); - assertEq(math.log_2(6, true), 3); - assertEq(math.log_2(7, true), 3); - assertEq(math.log_2(8, true), 3); - assertEq(math.log_2(9, true), 4); - assertEq(math.log_2(type(uint256).max, true), 256); + assertEq(math.log2(0, true), 0); + assertEq(math.log2(1, true), 0); + assertEq(math.log2(2, true), 1); + assertEq(math.log2(3, true), 2); + assertEq(math.log2(4, true), 2); + assertEq(math.log2(5, true), 3); + assertEq(math.log2(6, true), 3); + assertEq(math.log2(7, true), 3); + assertEq(math.log2(8, true), 3); + assertEq(math.log2(9, true), 4); + assertEq(math.log2(type(uint256).max, true), 256); } function testLog10RoundDown() public view { - assertEq(math.log_10(0, false), 0); - assertEq(math.log_10(1, false), 0); - assertEq(math.log_10(2, false), 0); - assertEq(math.log_10(9, false), 0); - assertEq(math.log_10(10, false), 1); - assertEq(math.log_10(11, false), 1); - assertEq(math.log_10(99, false), 1); - assertEq(math.log_10(100, false), 2); - assertEq(math.log_10(101, false), 2); - assertEq(math.log_10(999, false), 2); - assertEq(math.log_10(1_000, false), 3); - assertEq(math.log_10(1_001, false), 3); - assertEq(math.log_10(type(uint256).max, false), 77); + assertEq(math.log10(0, false), 0); + assertEq(math.log10(1, false), 0); + assertEq(math.log10(2, false), 0); + assertEq(math.log10(9, false), 0); + assertEq(math.log10(10, false), 1); + assertEq(math.log10(11, false), 1); + assertEq(math.log10(99, false), 1); + assertEq(math.log10(100, false), 2); + assertEq(math.log10(101, false), 2); + assertEq(math.log10(999, false), 2); + assertEq(math.log10(1_000, false), 3); + assertEq(math.log10(1_001, false), 3); + assertEq(math.log10(type(uint256).max, false), 77); } function testLog10RoundUp() public view { - assertEq(math.log_10(0, true), 0); - assertEq(math.log_10(1, true), 0); - assertEq(math.log_10(2, true), 1); - assertEq(math.log_10(9, true), 1); - assertEq(math.log_10(10, true), 1); - assertEq(math.log_10(11, true), 2); - assertEq(math.log_10(99, true), 2); - assertEq(math.log_10(100, true), 2); - assertEq(math.log_10(101, true), 3); - assertEq(math.log_10(999, true), 3); - assertEq(math.log_10(1_000, true), 3); - assertEq(math.log_10(1_001, true), 4); - assertEq(math.log_10(type(uint256).max, true), 78); + assertEq(math.log10(0, true), 0); + assertEq(math.log10(1, true), 0); + assertEq(math.log10(2, true), 1); + assertEq(math.log10(9, true), 1); + assertEq(math.log10(10, true), 1); + assertEq(math.log10(11, true), 2); + assertEq(math.log10(99, true), 2); + assertEq(math.log10(100, true), 2); + assertEq(math.log10(101, true), 3); + assertEq(math.log10(999, true), 3); + assertEq(math.log10(1_000, true), 3); + assertEq(math.log10(1_001, true), 4); + assertEq(math.log10(type(uint256).max, true), 78); } function testLog256RoundDown() public view { - assertEq(math.log_256(0, false), 0); - assertEq(math.log_256(1, false), 0); - assertEq(math.log_256(2, false), 0); - assertEq(math.log_256(255, false), 0); - assertEq(math.log_256(256, false), 1); - assertEq(math.log_256(257, false), 1); - assertEq(math.log_256(65_535, false), 1); - assertEq(math.log_256(65_536, false), 2); - assertEq(math.log_256(65_537, false), 2); - assertEq(math.log_256(type(uint256).max, false), 31); + assertEq(math.log256(0, false), 0); + assertEq(math.log256(1, false), 0); + assertEq(math.log256(2, false), 0); + assertEq(math.log256(255, false), 0); + assertEq(math.log256(256, false), 1); + assertEq(math.log256(257, false), 1); + assertEq(math.log256(65_535, false), 1); + assertEq(math.log256(65_536, false), 2); + assertEq(math.log256(65_537, false), 2); + assertEq(math.log256(type(uint256).max, false), 31); } function testLog256RoundUp() public view { - assertEq(math.log_256(0, true), 0); - assertEq(math.log_256(1, true), 0); - assertEq(math.log_256(2, true), 1); - assertEq(math.log_256(255, true), 1); - assertEq(math.log_256(256, true), 1); - assertEq(math.log_256(257, true), 2); - assertEq(math.log_256(65_535, true), 2); - assertEq(math.log_256(65_536, true), 2); - assertEq(math.log_256(65_537, true), 3); - assertEq(math.log_256(type(uint256).max, true), 32); + assertEq(math.log256(0, true), 0); + assertEq(math.log256(1, true), 0); + assertEq(math.log256(2, true), 1); + assertEq(math.log256(255, true), 1); + assertEq(math.log256(256, true), 1); + assertEq(math.log256(257, true), 2); + assertEq(math.log256(65_535, true), 2); + assertEq(math.log256(65_536, true), 2); + assertEq(math.log256(65_537, true), 3); + assertEq(math.log256(type(uint256).max, true), 32); } function testWadLn() public view { @@ -340,9 +343,9 @@ contract MathTest is Test { } function testWadLnNegativeValues() public { - vm.expectRevert(bytes("Math: wad_ln undefined")); + vm.expectRevert(bytes("math: wad_ln undefined")); math.wad_ln(-1); - vm.expectRevert(bytes("Math: wad_ln undefined")); + vm.expectRevert(bytes("math: wad_ln undefined")); math.wad_ln(type(int256).min); } @@ -376,9 +379,9 @@ contract MathTest is Test { } function testWadExpOverflow() public { - vm.expectRevert(bytes("Math: wad_exp overflow")); + vm.expectRevert(bytes("math: wad_exp overflow")); math.wad_exp(135_305_999_368_893_231_589); - vm.expectRevert(bytes("Math: wad_exp overflow")); + vm.expectRevert(bytes("math: wad_exp overflow")); math.wad_exp(type(int256).max); } @@ -565,7 +568,7 @@ contract MathTest is Test { * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/utils/math/Math.t.sol. */ function testFuzzLog2(uint256 x, bool roundup) public view { - uint256 result = math.log_2(x, roundup); + uint256 result = math.log2(x, roundup); if (x == 0) { assertEq(result, 0); } else if (result >= 256 || 2 ** result > x) { @@ -584,7 +587,7 @@ contract MathTest is Test { * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/utils/math/Math.t.sol. */ function testFuzzLog10(uint256 x, bool roundup) public view { - uint256 result = math.log_10(x, roundup); + uint256 result = math.log10(x, roundup); if (x == 0) { assertEq(result, 0); } else if (result >= 78 || 10 ** result > x) { @@ -603,7 +606,7 @@ contract MathTest is Test { * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/utils/math/Math.t.sol. */ function testFuzzLog256(uint256 x, bool roundup) public view { - uint256 result = math.log_256(x, roundup); + uint256 result = math.log256(x, roundup); if (x == 0) { assertEq(result, 0); } else if (result >= 32 || 256 ** result > x) { diff --git a/test/utils/MerkleProofVerification.t.sol b/test/utils/MerkleProofVerification.t.sol index cf4fc914..59f60c6c 100644 --- a/test/utils/MerkleProofVerification.t.sol +++ b/test/utils/MerkleProofVerification.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -277,8 +277,8 @@ contract MerkleProofVerificationTest is Test { function setUp() public { merkleProofVerification = IMerkleProofVerification( vyperDeployer.deployContract( - "src/snekmate/utils/", - "MerkleProofVerification" + "src/snekmate/utils/mocks/", + "merkle_proof_verification_mock" ) ); } @@ -447,7 +447,7 @@ contract MerkleProofVerificationTest is Test { * https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wprv-93r4-jj2p. * Note that 🐍 snekmate's implementation is not vulnerable by design, * as you cannot consume the out-of-bound `hashes` in Vyper. For further - * insights also, see the following Twitter thread: + * insights also, see the following X thread: * https://x.com/0xDACA/status/1669846430528286722. */ function testMaliciousMultiProofVerify() public { @@ -522,7 +522,7 @@ contract MerkleProofVerificationTest is Test { badLeavesDecodedSliced[0] = badLeavesDecoded[0]; badLeavesDecodedSliced[1] = badLeavesDecoded[2]; - vm.expectRevert(bytes("MerkleProof: invalid multiproof")); + vm.expectRevert(bytes("merkle_proof_verification: invalid multiproof")); merkleProofVerification.multi_proof_verify( badMultiProofDecodedSliced, badProofFlags, @@ -530,7 +530,7 @@ contract MerkleProofVerificationTest is Test { badLeavesDecoded ); - vm.expectRevert(bytes("MerkleProof: invalid multiproof")); + vm.expectRevert(bytes("merkle_proof_verification: invalid multiproof")); merkleProofVerification.multi_proof_verify( badMultiProofDecoded, badProofFlagsSliced, @@ -538,7 +538,7 @@ contract MerkleProofVerificationTest is Test { badLeavesDecoded ); - vm.expectRevert(bytes("MerkleProof: invalid multiproof")); + vm.expectRevert(bytes("merkle_proof_verification: invalid multiproof")); merkleProofVerification.multi_proof_verify( badMultiProofDecoded, badProofFlags, diff --git a/test/utils/MessageHashUtils.t.sol b/test/utils/MessageHashUtils.t.sol new file mode 100644 index 00000000..be9daec8 --- /dev/null +++ b/test/utils/MessageHashUtils.t.sol @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {VyperDeployer} from "utils/VyperDeployer.sol"; + +import {IMessageHashUtils} from "./interfaces/IMessageHashUtils.sol"; + +contract MessageHashUtilsTest is Test { + VyperDeployer private vyperDeployer = new VyperDeployer(); + + IMessageHashUtils private messageHashUtils; + + address private messageHashUtilsAddr; + + function setUp() public { + messageHashUtils = IMessageHashUtils( + vyperDeployer.deployContract( + "src/snekmate/utils/mocks/", + "message_hash_utils_mock" + ) + ); + messageHashUtilsAddr = address(messageHashUtils); + } + + function testEthSignedMessageHash() public view { + bytes32 hash = keccak256("WAGMI"); + bytes32 digest1 = messageHashUtils.to_eth_signed_message_hash(hash); + bytes32 digest2 = keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + assertEq(digest1, digest2); + } + + function testToDataWithIntendedValidatorHashSelf() public view { + bytes memory data = new bytes(42); + bytes32 digest1 = messageHashUtils + .to_data_with_intended_validator_hash_self(data); + bytes32 digest2 = keccak256( + abi.encodePacked("\x19\x00", messageHashUtilsAddr, data) + ); + assertEq(digest1, digest2); + } + + function testToDataWithIntendedValidatorHash() public { + address validator = makeAddr("intendedValidator"); + bytes memory data = new bytes(42); + bytes32 digest1 = messageHashUtils.to_data_with_intended_validator_hash( + validator, + data + ); + bytes32 digest2 = keccak256( + abi.encodePacked("\x19\x00", validator, data) + ); + assertEq(digest1, digest2); + } + + function testToTypedDataHash() public view { + bytes32 domainSeparator = keccak256("WAGMI"); + bytes32 structHash = keccak256("GM"); + bytes32 digest1 = messageHashUtils.to_typed_data_hash( + domainSeparator, + structHash + ); + bytes32 digest2 = keccak256( + abi.encodePacked("\x19\x01", domainSeparator, structHash) + ); + assertEq(digest1, digest2); + } + + function testFuzzEthSignedMessageHash(string calldata message) public view { + bytes32 hash = keccak256(abi.encode(message)); + bytes32 digest1 = messageHashUtils.to_eth_signed_message_hash(hash); + bytes32 digest2 = keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", hash) + ); + assertEq(digest1, digest2); + } + + function testFuzzToDataWithIntendedValidatorHashSelf( + bytes calldata data + ) public view { + bytes32 digest1 = messageHashUtils + .to_data_with_intended_validator_hash_self(data); + bytes32 digest2 = keccak256( + abi.encodePacked("\x19\x00", messageHashUtilsAddr, data) + ); + assertEq(digest1, digest2); + } + + function testFuzzToDataWithIntendedValidatorHash( + address validator, + bytes calldata data + ) public view { + bytes32 digest1 = messageHashUtils.to_data_with_intended_validator_hash( + validator, + data + ); + bytes32 digest2 = keccak256( + abi.encodePacked("\x19\x00", validator, data) + ); + assertEq(digest1, digest2); + } + + function testFuzzToTypedDataHash( + string calldata domainSeparatorPlain, + string calldata structPlain + ) public view { + bytes32 domainSeparator = keccak256(abi.encode(domainSeparatorPlain)); + bytes32 structHash = keccak256(abi.encode(structPlain)); + bytes32 digest1 = messageHashUtils.to_typed_data_hash( + domainSeparator, + structHash + ); + bytes32 digest2 = keccak256( + abi.encodePacked("\x19\x01", domainSeparator, structHash) + ); + assertEq(digest1, digest2); + } +} diff --git a/test/utils/Multicall.t.sol b/test/utils/Multicall.t.sol index 8f8f93db..6416c53c 100644 --- a/test/utils/Multicall.t.sol +++ b/test/utils/Multicall.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -21,7 +21,10 @@ contract MulticallTest is Test { function setUp() public { multicall = IMulticall( - vyperDeployer.deployContract("src/snekmate/utils/", "Multicall") + vyperDeployer.deployContract( + "src/snekmate/utils/mocks/", + "multicall_mock" + ) ); } @@ -195,7 +198,7 @@ contract MulticallTest is Test { abi.encodeWithSignature("transferEther(address)", etherReceiverAddr) ); - vm.expectRevert(bytes("Multicall: value mismatch")); + vm.expectRevert(bytes("multicall: value mismatch")); /** * @dev We don't send any `msg.value`. */ diff --git a/test/utils/P256.t.sol b/test/utils/P256.t.sol new file mode 100644 index 00000000..19d0fccb --- /dev/null +++ b/test/utils/P256.t.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {VyperDeployer} from "utils/VyperDeployer.sol"; + +import {BytesLib} from "solidity-bytes-utils/BytesLib.sol"; +import {FCL_ecdsa_utils} from "fresh-crypto-lib/FCL_ecdsa_utils.sol"; + +import {IP256} from "./interfaces/IP256.sol"; + +contract P256Test is Test { + using BytesLib for bytes; + using stdJson for string; + + uint256 private constant _MALLEABILITY_THRESHOLD = + 57_896_044_605_178_124_381_348_723_474_703_786_764_998_477_612_067_880_171_211_129_530_534_256_022_184; + /* solhint-disable const-name-snakecase */ + bytes32 private constant hashValid = + 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023; + uint256 private constant rValid = + 19_738_613_187_745_101_558_623_338_726_804_762_177_711_919_211_234_071_563_652_772_152_683_725_073_944; + uint256 private constant sValid = + 34_753_961_278_895_633_991_577_816_754_222_591_531_863_837_041_401_341_770_838_584_739_693_604_822_390; + uint256 private constant qxValid = + 18_614_955_573_315_897_657_680_976_650_685_450_080_931_919_913_269_223_958_732_452_353_593_824_192_568; + uint256 private constant qyValid = + 90_223_116_347_859_880_166_570_198_725_387_569_567_414_254_547_569_925_327_988_539_833_150_573_990_206; + uint256 private constant p = + 115_792_089_210_356_248_762_697_446_949_407_573_530_086_143_415_290_314_195_533_631_308_867_097_853_951; + /* solhint-enable const-name-snakecase */ + + VyperDeployer private vyperDeployer = new VyperDeployer(); + + // solhint-disable-next-line var-name-mixedcase + IP256 private P256; + + function setUp() public { + P256 = IP256( + vyperDeployer.deployContract( + "src/snekmate/utils/mocks/", + "p256_mock" + ) + ); + } + + function testVerifyWithValidSignature() public view { + assertTrue( + P256.verify_sig(hashValid, rValid, sValid, qxValid, qyValid) + ); + assertTrue( + !P256.verify_sig(hashValid, rValid, sValid, qxValid + 1, qyValid) + ); + } + + function testVerifyWithZeroInputs() public view { + assertTrue(!P256.verify_sig(bytes32(0), 0, 0, 0, 0)); + } + + function testVerifyWithOutOfBoundsPublicKey() public view { + assertTrue(!P256.verify_sig(hashValid, rValid, sValid, 0, 1)); + assertTrue(!P256.verify_sig(hashValid, rValid, sValid, 1, 0)); + assertTrue(!P256.verify_sig(hashValid, rValid, sValid, 1, p)); + assertTrue(!P256.verify_sig(hashValid, rValid, sValid, p, 1)); + /** + * @dev The value `p-1` is technically in-bounds, but the point is not on the curve. + */ + assertTrue(!P256.verify_sig(hashValid, rValid, sValid, p - 1, 1)); + } + + function testVerifyWithFlippedValues() public view { + assertTrue( + P256.verify_sig(hashValid, rValid, sValid, qxValid, qyValid) + ); + assertTrue( + !P256.verify_sig(hashValid, sValid, rValid, qxValid, qyValid) + ); + assertTrue( + !P256.verify_sig(hashValid, rValid, sValid, qyValid, qxValid) + ); + assertTrue( + !P256.verify_sig(hashValid, sValid, rValid, qyValid, qxValid) + ); + } + + function testVerifyWithInvalidSignature() public view { + assertTrue( + !P256.verify_sig( + keccak256("WAGMI"), + rValid, + sValid, + qxValid, + qyValid + ) + ); + } + + function testVerifyWycheproofData() public { + string memory file = "test/utils/test-data/wycheproof.jsonl"; + while (true) { + string memory vector = vm.readLine(file); + if (bytes(vector).length == 0) { + break; + } + + uint256 r = uint256(vector.readBytes32(".r")); + uint256 s = uint256(vector.readBytes32(".s")); + uint256 x = uint256(vector.readBytes32(".x")); + uint256 y = uint256(vector.readBytes32(".y")); + bytes32 hash = vector.readBytes32(".hash"); + + if (uint256(s) <= _MALLEABILITY_THRESHOLD) { + assertEq( + P256.verify_sig(hash, r, s, x, y), + vector.readBool(".valid") + ); + } else { + vm.expectRevert(bytes("p256: invalid signature `s` value")); + P256.verify_sig(hash, r, s, x, y); + } + } + } + + function testVerifyWithTooHighSValue() public { + uint256 sTooHigh = sValid + _MALLEABILITY_THRESHOLD; + vm.expectRevert(bytes("p256: invalid signature `s` value")); + P256.verify_sig(hashValid, rValid, sTooHigh, qxValid, qyValid); + } + + function testFuzzVerifyWithValidSignature( + string calldata signer, + string calldata message + ) public { + (, uint256 key) = makeAddrAndKey(signer); + bytes32 hash = keccak256(abi.encode(message)); + (bytes32 r, bytes32 s) = vm.signP256(key, hash); + (uint256 qx, uint256 qy) = FCL_ecdsa_utils.ecdsa_derivKpub(key); + if (uint256(s) <= _MALLEABILITY_THRESHOLD) { + assertTrue(P256.verify_sig(hash, uint256(r), uint256(s), qx, qy)); + } else { + vm.expectRevert(bytes("p256: invalid signature `s` value")); + P256.verify_sig(hash, uint256(r), uint256(s), qx, qy); + } + } +} diff --git a/test/utils/SignatureChecker.t.sol b/test/utils/SignatureChecker.t.sol index 5594b81c..b8a8f309 100644 --- a/test/utils/SignatureChecker.t.sol +++ b/test/utils/SignatureChecker.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; @@ -23,8 +23,8 @@ contract SignatureCheckerTest is Test { function setUp() public { signatureChecker = ISignatureChecker( vyperDeployer.deployContract( - "src/snekmate/utils/", - "SignatureChecker" + "src/snekmate/utils/mocks/", + "signature_checker_mock" ) ); } @@ -97,7 +97,7 @@ contract SignatureCheckerTest is Test { bytes32 hash = keccak256("WAGMI"); (, bytes32 r, bytes32 s) = vm.sign(key, hash); bytes memory signatureInvalid = abi.encodePacked(r, s, bytes1(0xa0)); - vm.expectRevert(bytes("ECDSA: invalid signature")); + vm.expectRevert(bytes("ecdsa: invalid signature")); signatureChecker.is_valid_signature_now(alice, hash, signatureInvalid); assertTrue( !signatureChecker.is_valid_ERC1271_signature_now( @@ -119,7 +119,7 @@ contract SignatureCheckerTest is Test { bytes32(sTooHigh), v ); - vm.expectRevert(bytes("ECDSA: invalid signature `s` value")); + vm.expectRevert(bytes("ecdsa: invalid signature `s` value")); signatureChecker.is_valid_signature_now(alice, hash, signatureInvalid); assertTrue( !signatureChecker.is_valid_ERC1271_signature_now( @@ -195,11 +195,12 @@ contract SignatureCheckerTest is Test { bytes32 hash = keccak256("WAGMI"); (, bytes32 r, bytes32 s) = vm.sign(key, hash); bytes memory signatureInvalid = abi.encodePacked(r, s, bytes1(0xa0)); - vm.expectRevert(bytes("ECDSA: invalid signature")); - signatureChecker.is_valid_signature_now( - walletAddr, - hash, - signatureInvalid + assertTrue( + !signatureChecker.is_valid_signature_now( + walletAddr, + hash, + signatureInvalid + ) ); assertTrue( !signatureChecker.is_valid_ERC1271_signature_now( diff --git a/test/utils/halmos/MathTestHalmos.t.sol b/test/utils/halmos/MathTestHalmos.t.sol new file mode 100644 index 00000000..634ca1ad --- /dev/null +++ b/test/utils/halmos/MathTestHalmos.t.sol @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {SymTest} from "halmos-cheatcodes/SymTest.sol"; +import {VyperDeployer} from "utils/VyperDeployer.sol"; + +import {Math} from "openzeppelin/utils/math/Math.sol"; +import {FixedPointMathLib} from "solady/utils/FixedPointMathLib.sol"; + +import {IMath} from "../interfaces/IMath.sol"; + +/** + * @dev Sets the timeout (in milliseconds) for solving assertion + * violation conditions; `0` means no timeout. + * @notice Halmos currently does not support the new native `assert` + * cheatcodes in `forge-std` `v1.8.0` and above. + * @custom:halmos --solver-timeout-assertion 0 + */ +contract MathTestHalmos is Test, SymTest { + VyperDeployer private vyperDeployer = new VyperDeployer(); + + IMath private math; + + /** + * @dev Sets timeout (in milliseconds) for solving branching + * conditions; `0` means no timeout. + * @custom:halmos --solver-timeout-branching 1000 + */ + function setUp() public { + /** + * @dev Halmos does not currently work with the latest Vyper jump-table-based + * dispatchers: https://github.com/a16z/halmos/issues/253. For Halmos-based tests, + * we therefore disable the optimiser. Furthermore, Halmos does not currently + * work with the EVM version `cancun`: https://github.com/a16z/halmos/issues/290. + * For Halmos-based tests, we therefore use the EVM version `shanghai`. + */ + math = IMath( + vyperDeployer.deployContract( + "src/snekmate/utils/mocks/", + "math_mock", + "shanghai", + "none" + ) + ); + } + + function testHalmosAssertUint256Average(uint256 x, uint256 y) public view { + assert(math.uint256_average(x, y) == Math.average(x, y)); + } + + function testHalmosAssertInt256Average(int256 x, int256 y) public view { + assert(math.int256_average(x, y) == FixedPointMathLib.avg(x, y)); + } + + function testHalmosAssertCeilDiv(uint256 x, uint256 y) public view { + assert(math.ceil_div(x, y) == Math.ceilDiv(x, y)); + } + + function testHalmosAssertSignum(int256 x) public view { + int256 signum; + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + signum := sub(sgt(x, 0), slt(x, 0)) + } + assert(math.signum(x) == signum); + } + + /** + * @dev Currently commented out, as the timeout for the Z3 solver does not work for + * the queries of this test, where the Z3 solver is constantly running and consumes + * a lot of memory, causing the CI to crash due to out of memory. + */ + // function testHalmosAssertMulDiv( + // uint256 x, + // uint256 y, + // uint256 denominator, + // Math.Rounding rounding + // ) public view { + // assert( + // math.mul_div(x, y, denominator, Math.unsignedRoundsUp(rounding)) == + // Math.mulDiv(x, y, denominator, rounding) + // ); + // } + + function testHalmosAssertLog2( + uint256 x, + Math.Rounding rounding + ) public view { + assert( + math.log2(x, Math.unsignedRoundsUp(rounding)) == + Math.log2(x, rounding) + ); + } + + function testHalmosAssertLog10( + uint256 x, + Math.Rounding rounding + ) public view { + assert( + math.log10(x, Math.unsignedRoundsUp(rounding)) == + Math.log10(x, rounding) + ); + } + + function testHalmosAssertLog256( + uint256 x, + Math.Rounding rounding + ) public view { + assert( + math.log256(x, Math.unsignedRoundsUp(rounding)) == + Math.log256(x, rounding) + ); + } + + /** + * @dev Currently commented out, as the timeout for the Z3 solver does not work for + * the queries of this test, where the Z3 solver is constantly running and consumes + * a lot of memory, causing the CI to crash due to out of memory. + */ + // function testHalmosAssertWadLn(int256 x) public view { + // assert(math.wad_ln(x) == FixedPointMathLib.lnWad(x)); + // } + + /** + * @dev Currently commented out, as the timeout for the Z3 solver does not work for + * the queries of this test, where the Z3 solver is constantly running and consumes + * a lot of memory, causing the CI to crash due to out of memory. + */ + // function testHalmosAssertWadExp(int256 x) public view { + // assert(math.wad_exp(x) == FixedPointMathLib.expWad(x)); + // } + + /** + * @dev Currently commented out, as the timeout for the Z3 solver does not work for + * the queries of this test, where the Z3 solver is constantly running and consumes + * a lot of memory, causing the CI to crash due to out of memory. + */ + // function testHalmosAssertCbrt(uint256 x, bool roundup) public view { + // if (!roundup) { + // assert(math.cbrt(x, roundup) == FixedPointMathLib.cbrt(x)); + // } else { + // assert( + // math.cbrt(x, roundup) >= FixedPointMathLib.cbrt(x) && + // math.cbrt(x, roundup) <= FixedPointMathLib.cbrt(x) + 1 + // ); + // } + // } + + /** + * @dev Currently commented out, as the timeout for the Z3 solver does not work for + * the queries of this test, where the Z3 solver is constantly running and consumes + * a lot of memory, causing the CI to crash due to out of memory. + */ + // function testHalmosAssertWadCbrt(uint256 x) public view { + // assert(math.wad_cbrt(x) == FixedPointMathLib.cbrtWad(x)); + // } +} diff --git a/test/utils/interfaces/IBase64.sol b/test/utils/interfaces/IBase64.sol index 0067e42c..2ab5131e 100644 --- a/test/utils/interfaces/IBase64.sol +++ b/test/utils/interfaces/IBase64.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface IBase64 { function encode( diff --git a/test/utils/interfaces/IBatchDistributor.sol b/test/utils/interfaces/IBatchDistributor.sol index a5142f90..1f2b131d 100644 --- a/test/utils/interfaces/IBatchDistributor.sol +++ b/test/utils/interfaces/IBatchDistributor.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol"; diff --git a/test/utils/interfaces/ICreate2Address.sol b/test/utils/interfaces/ICreate2Address.sol index d5717e13..2bab0cb7 100644 --- a/test/utils/interfaces/ICreate2Address.sol +++ b/test/utils/interfaces/ICreate2Address.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface ICreate2Address { function compute_address_self( diff --git a/test/utils/interfaces/ICreateAddress.sol b/test/utils/interfaces/ICreateAddress.sol index 4ba0ce81..d35d7db2 100644 --- a/test/utils/interfaces/ICreateAddress.sol +++ b/test/utils/interfaces/ICreateAddress.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface ICreateAddress { function compute_address_rlp_self( diff --git a/test/utils/interfaces/IECDSA.sol b/test/utils/interfaces/IECDSA.sol index 88acce81..8159ea68 100644 --- a/test/utils/interfaces/IECDSA.sol +++ b/test/utils/interfaces/IECDSA.sol @@ -1,27 +1,9 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface IECDSA { function recover_sig( bytes32 hash, bytes calldata signature ) external pure returns (address); - - function to_eth_signed_message_hash( - bytes32 hash - ) external pure returns (bytes32); - - function to_typed_data_hash( - bytes32 domainSeparator, - bytes32 structHash - ) external pure returns (bytes32); - - function to_data_with_intended_validator_hash_self( - bytes calldata data - ) external view returns (bytes32); - - function to_data_with_intended_validator_hash( - address validator, - bytes calldata data - ) external pure returns (bytes32); } diff --git a/test/utils/interfaces/IEIP712DomainSeparator.sol b/test/utils/interfaces/IEIP712DomainSeparator.sol index dfe1a861..ebcb7152 100644 --- a/test/utils/interfaces/IEIP712DomainSeparator.sol +++ b/test/utils/interfaces/IEIP712DomainSeparator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC5267} from "openzeppelin/interfaces/IERC5267.sol"; diff --git a/test/utils/interfaces/IMath.sol b/test/utils/interfaces/IMath.sol index f5a69e19..6698305a 100644 --- a/test/utils/interfaces/IMath.sol +++ b/test/utils/interfaces/IMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface IMath { function uint256_average( @@ -20,11 +20,11 @@ interface IMath { bool roundup ) external pure returns (uint256); - function log_2(uint256 x, bool roundup) external pure returns (uint256); + function log2(uint256 x, bool roundup) external pure returns (uint256); - function log_10(uint256 x, bool roundup) external pure returns (uint256); + function log10(uint256 x, bool roundup) external pure returns (uint256); - function log_256(uint256 x, bool roundup) external pure returns (uint256); + function log256(uint256 x, bool roundup) external pure returns (uint256); function wad_ln(int256 x) external pure returns (int256); diff --git a/test/utils/interfaces/IMerkleProofVerification.sol b/test/utils/interfaces/IMerkleProofVerification.sol index 7e1f98e4..f46b0c46 100644 --- a/test/utils/interfaces/IMerkleProofVerification.sol +++ b/test/utils/interfaces/IMerkleProofVerification.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface IMerkleProofVerification { function verify( diff --git a/test/utils/interfaces/IMessageHashUtils.sol b/test/utils/interfaces/IMessageHashUtils.sol new file mode 100644 index 00000000..f7b80d37 --- /dev/null +++ b/test/utils/interfaces/IMessageHashUtils.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +interface IMessageHashUtils { + function to_eth_signed_message_hash( + bytes32 hash + ) external pure returns (bytes32); + + function to_data_with_intended_validator_hash_self( + bytes calldata data + ) external view returns (bytes32); + + function to_data_with_intended_validator_hash( + address validator, + bytes calldata data + ) external pure returns (bytes32); + + function to_typed_data_hash( + bytes32 domainSeparator, + bytes32 structHash + ) external pure returns (bytes32); +} diff --git a/test/utils/interfaces/IMulticall.sol b/test/utils/interfaces/IMulticall.sol index bd6143c2..55914490 100644 --- a/test/utils/interfaces/IMulticall.sol +++ b/test/utils/interfaces/IMulticall.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface IMulticall { struct Batch { diff --git a/test/utils/interfaces/IP256.sol b/test/utils/interfaces/IP256.sol new file mode 100644 index 00000000..3fd7cf24 --- /dev/null +++ b/test/utils/interfaces/IP256.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: WTFPL +pragma solidity ^0.8.26; + +interface IP256 { + function verify_sig( + bytes32 hash, + uint256 r, + uint256 s, + uint256 qx, + uint256 qy + ) external view returns (bool); +} diff --git a/test/utils/interfaces/ISignatureChecker.sol b/test/utils/interfaces/ISignatureChecker.sol index 6f79abbb..a15b1926 100644 --- a/test/utils/interfaces/ISignatureChecker.sol +++ b/test/utils/interfaces/ISignatureChecker.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: WTFPL -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; interface ISignatureChecker { function IERC1271_ISVALIDSIGNATURE_SELECTOR() diff --git a/test/utils/mocks/Create2Impl.sol b/test/utils/mocks/Create2Impl.sol index eabfd8fd..41bded88 100644 --- a/test/utils/mocks/Create2Impl.sol +++ b/test/utils/mocks/Create2Impl.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Create2} from "openzeppelin/utils/Create2.sol"; diff --git a/test/utils/mocks/ERC1271MaliciousMock.sol b/test/utils/mocks/ERC1271MaliciousMock.sol index d7084f76..f7ba58c3 100644 --- a/test/utils/mocks/ERC1271MaliciousMock.sol +++ b/test/utils/mocks/ERC1271MaliciousMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {IERC1271} from "openzeppelin/interfaces/IERC1271.sol"; @@ -20,7 +20,7 @@ contract ERC1271MaliciousMock is IERC1271 { bytes memory ) public pure override returns (bytes4) { // solhint-disable-next-line no-inline-assembly - assembly { + assembly ("memory-safe") { mstore( 0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/utils/mocks/ERC1271WalletMock.sol b/test/utils/mocks/ERC1271WalletMock.sol index dcd2bba0..d174d82d 100644 --- a/test/utils/mocks/ERC1271WalletMock.sol +++ b/test/utils/mocks/ERC1271WalletMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {Ownable} from "openzeppelin/access/Ownable.sol"; import {IERC1271} from "openzeppelin/interfaces/IERC1271.sol"; diff --git a/test/utils/mocks/ERC20Mock.sol b/test/utils/mocks/ERC20Mock.sol index 1d1c7728..feb581f6 100644 --- a/test/utils/mocks/ERC20Mock.sol +++ b/test/utils/mocks/ERC20Mock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; import {ERC20} from "openzeppelin/token/ERC20/ERC20.sol"; diff --git a/test/utils/mocks/EtherReceiver.sol b/test/utils/mocks/EtherReceiver.sol index 1e296309..3e7e714e 100644 --- a/test/utils/mocks/EtherReceiver.sol +++ b/test/utils/mocks/EtherReceiver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; /** * @title EtherReceiver diff --git a/test/utils/mocks/MockCallee.sol b/test/utils/mocks/MockCallee.sol index 908b96dd..75aa49bf 100644 --- a/test/utils/mocks/MockCallee.sol +++ b/test/utils/mocks/MockCallee.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity ^0.8.26; /** * @dev Error that occurs when a method reverts. @@ -16,7 +16,7 @@ error Reverted(address emitter); */ contract MockCallee { uint256 public number; - address private self = address(this); + address private _self = address(this); /** * @dev Stores a uint256 value in the variable `number`. @@ -43,7 +43,7 @@ contract MockCallee { * @dev A function that simply reverts. */ function thisMethodReverts() public view { - revert Reverted(self); + revert Reverted(_self); } /** @@ -53,6 +53,6 @@ contract MockCallee { function transferEther(address target) public payable { // solhint-disable-next-line avoid-low-level-calls (bool ok, ) = target.call{value: msg.value}(""); - if (!ok) revert Reverted(self); + if (!ok) revert Reverted(_self); } } diff --git a/test/utils/mocks/ReentrancyMocks.sol b/test/utils/mocks/ReentrancyMocks.sol new file mode 100644 index 00000000..ac086fba --- /dev/null +++ b/test/utils/mocks/ReentrancyMocks.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +import {IBatchDistributor} from "../interfaces/IBatchDistributor.sol"; +import {ERC20Mock} from "./ERC20Mock.sol"; + +/** + * @title DistributeEtherReentrancyMock + * @author pcaversaccio + * @dev Allows to mock a single-function reentrancy via the function `distribute_ether` + * in `BatchDistributor`. + */ +contract DistributeEtherReentrancyMock { + address private constant _FUND_RECEIVER = address(1_337); + uint256 private _counter; + + /** + * @dev Reenters the function `distribute_ether` in `BatchDistributor` once. + */ + // solhint-disable-next-line no-complex-fallback + receive() external payable { + if (_counter == 0) { + IBatchDistributor.Transaction[] + memory transaction = new IBatchDistributor.Transaction[](1); + transaction[0] = IBatchDistributor.Transaction({ + recipient: _FUND_RECEIVER, + amount: msg.value + }); + IBatchDistributor.Batch memory batch = IBatchDistributor.Batch({ + txns: transaction + }); + + // solhint-disable-next-line avoid-low-level-calls + (bool reentered, ) = msg.sender.call{value: msg.value}( + abi.encodeWithSelector( + IBatchDistributor.distribute_ether.selector, + batch + ) + ); + if (!reentered) { + // solhint-disable-next-line reason-string, gas-custom-errors + revert( + "DistributeEtherReentrancyMock: reentrancy unsuccessful" + ); + } + _counter = 1; + } + } +} + +/** + * @title DistributeTokenReentrancyMock + * @author pcaversaccio + * @dev Allows to mock a cross-function reentrancy via the functions `distribute_ether` + * and `distribute_token` in `BatchDistributor`. + */ +contract DistributeTokenReentrancyMock { + address private constant _FUND_RECEIVER = address(1_337); + uint256 private _counter; + + /** + * @dev Reenters the function `distribute_token` in `BatchDistributor` once. + */ + // solhint-disable-next-line no-complex-fallback + receive() external payable { + if (_counter == 0) { + string memory arg1 = "MyToken"; + string memory arg2 = "MTKN"; + address arg3 = address(this); + uint256 arg4 = 100; + ERC20Mock erc20Mock = new ERC20Mock(arg1, arg2, arg3, arg4); + erc20Mock.approve(msg.sender, arg4); + + IBatchDistributor.Transaction[] + memory transaction = new IBatchDistributor.Transaction[](1); + transaction[0] = IBatchDistributor.Transaction({ + recipient: _FUND_RECEIVER, + amount: 30 + }); + IBatchDistributor.Batch memory batch = IBatchDistributor.Batch({ + txns: transaction + }); + + // solhint-disable-next-line avoid-low-level-calls + (bool reentered, ) = msg.sender.call( + abi.encodeWithSelector( + IBatchDistributor.distribute_token.selector, + erc20Mock, + batch + ) + ); + if (!reentered) { + // solhint-disable-next-line reason-string, gas-custom-errors + revert( + "DistributeTokenReentrancyMock: reentrancy unsuccessful" + ); + } + _counter = 1; + } + } +} diff --git a/test/utils/test-data/wycheproof.jsonl b/test/utils/test-data/wycheproof.jsonl new file mode 100644 index 00000000..eb6dd5b8 --- /dev/null +++ b/test/utils/test-data/wycheproof.jsonl @@ -0,0 +1,778 @@ +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"4cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #1: signature malleability"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5740946b2a147f59262ee6f5bc90bd01ed280528b62b3aed5fc93f06f739","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #3: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5741946b2a137f59262ee6f5bc91001af27a5e1117a64733950642a3d1e8","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #5: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"4cd60b865d442f5a3c7b11eb6c4e0ae79578ec6353a20bf783ecb4b6ea97b825","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #8: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #9: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #10: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #11: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #12: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #13: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #14: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #15: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #16: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #17: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #18: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #19: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #20: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #21: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #22: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #23: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #24: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #25: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #26: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #27: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #28: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #29: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #30: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #31: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #32: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #33: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #34: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #35: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #36: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #37: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #38: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #39: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #40: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #41: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #42: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #43: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #44: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #45: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #46: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #47: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #48: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #49: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #50: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #51: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #52: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #53: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #54: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #55: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #56: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #57: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"64a1aab5000d0e804f3e2fc02bdee9be8ff312334e2ba16d11547c97711c898e","s":"6af015971cc30be6d1a206d4e013e0997772a2f91d73286ffd683b9bb2cf4f1b","hash":"70239dd877f7c944c422f44dea4ed1a52f2627416faf2f072fa50c772ed6f807","valid":true,"msg":"3639383139","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #58: Edge case for Shamir multiplication"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"16aea964a2f6506d6f78c81c91fc7e8bded7d397738448de1e19a0ec580bf266","s":"252cd762130c6667cfe8b7bc47d27d78391e8e80c578d1cd38c3ff033be928e9","hash":"00000000690ed426ccf17803ebe2bd0884bcd58a1bb5e7477ead3645f356e7a9","valid":true,"msg":"343236343739373234","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #59: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9cc98be2347d469bf476dfc26b9b733df2d26d6ef524af917c665baccb23c882","s":"093496459effe2d8d70727b82462f61d0ec1b7847929d10ea631dacb16b56c32","hash":"7300000000213f2a525c6035725235c2f696ad3ebb5ee47f140697ad25770d91","valid":true,"msg":"37313338363834383931","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #60: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"73b3c90ecd390028058164524dde892703dce3dea0d53fa8093999f07ab8aa43","s":"2f67b0b8e20636695bb7d8bf0a651c802ed25a395387b5f4188c0c4075c88634","hash":"ddf2000000005e0be0635b245f0b97978afd25daadeb3edb4a0161c27fe06045","valid":true,"msg":"3130333539333331363638","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #61: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bfab3098252847b328fadf2f89b95c851a7f0eb390763378f37e90119d5ba3dd","s":"bdd64e234e832b1067c2d058ccb44d978195ccebb65c2aaf1e2da9b8b4987e3b","hash":"67ab1900000000784769c4ecb9e164d6642b8499588b89855be1ec355d0841a0","valid":true,"msg":"33393439343031323135","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #62: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"204a9784074b246d8bf8bf04a4ceb1c1f1c9aaab168b1596d17093c5cd21d2cd","s":"51cce41670636783dc06a759c8847868a406c2506fe17975582fe648d1d88b52","hash":"a2bf09460000000076d7dbeffe125eaf02095dff252ee905e296b6350fc311cf","valid":true,"msg":"31333434323933303739","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #63: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ed66dc34f551ac82f63d4aa4f81fe2cb0031a91d1314f835027bca0f1ceeaa03","s":"99ca123aa09b13cd194a422e18d5fda167623c3f6e5d4d6abb8953d67c0c48c7","hash":"3554e827c700000000e1e75e624a06b3a0a353171160858129e15c544e4f0e65","valid":true,"msg":"33373036323131373132","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #64: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"060b700bef665c68899d44f2356a578d126b062023ccc3c056bf0f60a237012b","s":"8d186c027832965f4fcc78a3366ca95dedbb410cbef3f26d6be5d581c11d3610","hash":"9b6cd3b812610000000026941a0f0bb53255ea4c9fd0cb3426e3a54b9fc6965c","valid":true,"msg":"333433363838373132","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #65: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9f6adfe8d5eb5b2c24d7aa7934b6cf29c93ea76cd313c9132bb0c8e38c96831d","s":"b26a9c9e40e55ee0890c944cf271756c906a33e66b5bd15e051593883b5e9902","hash":"883ae39f50bf0100000000e7561c26fc82a52baa51c71ca877162f93c4ae0186","valid":true,"msg":"31333531353330333730","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #66: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a1af03ca91677b673ad2f33615e56174a1abf6da168cebfa8868f4ba273f16b7","s":"20aa73ffe48afa6435cd258b173d0c2377d69022e7d098d75caf24c8c5e06b1c","hash":"a1ce5d6e5ecaf28b0000000000fa7cd010540f420fb4ff7401fe9fce011d0ba6","valid":true,"msg":"36353533323033313236","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #67: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"fdc70602766f8eed11a6c99a71c973d5659355507b843da6e327a28c11893db9","s":"3df5349688a085b137b1eacf456a9e9e0f6d15ec0078ca60a7f83f2b10d21350","hash":"8ea5f645f373f580930000000038345397330012a8ee836c5494cdffd5ee8054","valid":true,"msg":"31353634333436363033","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #68: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"b516a314f2fce530d6537f6a6c49966c23456f63c643cf8e0dc738f7b876e675","s":"d39ffd033c92b6d717dd536fbc5efdf1967c4bd80954479ba66b0120cd16fff2","hash":"660570d323e9f75fa734000000008792d65ce93eabb7d60d8d9c1bbdcb5ef305","valid":true,"msg":"34343239353339313137","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #69: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"3b2cbf046eac45842ecb7984d475831582717bebb6492fd0a485c101e29ff0a8","s":"4c9b7b47a98b0f82de512bc9313aaf51701099cac5f76e68c8595fc1c1d99258","hash":"d0462673154cce587dde8800000000e98d35f1f45cf9c3bf46ada2de4c568c34","valid":true,"msg":"3130393533323631333531","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #70: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"30c87d35e636f540841f14af54e2f9edd79d0312cfa1ab656c3fb15bfde48dcf","s":"47c15a5a82d24b75c85a692bd6ecafeb71409ede23efd08e0db9abf6340677ed","hash":"bd90640269a7822680cedfef000000000caef15a6171059ab83e7b4418d7278f","valid":true,"msg":"35393837333530303431","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #71: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"38686ff0fda2cef6bc43b58cfe6647b9e2e8176d168dec3c68ff262113760f52","s":"067ec3b651f422669601662167fa8717e976e2db5e6a4cf7c2ddabb3fde9d67d","hash":"33239a52d72f1311512e41222a00000000d2dcceb301c54b4beae8e284788a73","valid":true,"msg":"33343633303036383738","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #72: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"44a3e23bf314f2b344fc25c7f2de8b6af3e17d27f5ee844b225985ab6e2775cf","s":"2d48e223205e98041ddc87be532abed584f0411f5729500493c9cc3f4dd15e86","hash":"b8d64fbcd4a1c10f1365d4e6d95c000000007ee4a21a1cbe1dc84c2d941ffaf1","valid":true,"msg":"39383137333230323837","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #73: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ded5b7ec8e90e7bf11f967a3d95110c41b99db3b5aa8d330eb9d638781688e9","s":"7d5792c53628155e1bfc46fb1a67e3088de049c328ae1f44ec69238a009808f9","hash":"01603d3982bf77d7a3fef3183ed092000000003a227420db4088b20fe0e9d84a","valid":true,"msg":"33323232303431303436","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #74: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bdae7bcb580bf335efd3bc3d31870f923eaccafcd40ec2f605976f15137d8b8f","s":"f6dfa12f19e525270b0106eecfe257499f373a4fb318994f24838122ce7ec3c7","hash":"9ea6994f1e0384c8599aa02e6cf66d9c000000004d89ef50b7e9eb0cfbff7363","valid":true,"msg":"36363636333037313034","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #75: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"50f9c4f0cd6940e162720957ffff513799209b78596956d21ece251c2401f1c6","s":"d7033a0a787d338e889defaaabb106b95a4355e411a59c32aa5167dfab244726","hash":"d03215a8401bcf16693979371a01068a4700000000e2fa5bf692bc670905b18c","valid":true,"msg":"31303335393531383938","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #76: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"f612820687604fa01906066a378d67540982e29575d019aabe90924ead5c860d","s":"3f9367702dd7dd4f75ea98afd20e328a1a99f4857b316525328230ce294b0fef","hash":"307bfaaffb650c889c84bf83f0300e5dc87e000000008408fd5f64b582e3bb14","valid":true,"msg":"31383436353937313935","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #77: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9505e407657d6e8bc93db5da7aa6f5081f61980c1949f56b0f2f507da5782a7a","s":"c60d31904e3669738ffbeccab6c3656c08e0ed5cb92b3cfa5e7f71784f9c5021","hash":"bab5c4f4df540d7b33324d36bb0c157551527c00000000e4af574bb4d54ea6b8","valid":true,"msg":"33313336303436313839","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #78: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bbd16fbbb656b6d0d83e6a7787cd691b08735aed371732723e1c68a40404517d","s":"9d8e35dba96028b7787d91315be675877d2d097be5e8ee34560e3e7fd25c0f00","hash":"d4ba47f6ae28f274e4f58d8036f9c36ec2456f5b00000000c3b869197ef5e15e","valid":true,"msg":"32363633373834323534","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #79: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ec9760122db98fd06ea76848d35a6da442d2ceef7559a30cf57c61e92df327e","s":"7ab271da90859479701fccf86e462ee3393fb6814c27b760c4963625c0a19878","hash":"79fd19c7235ea212f29f1fa00984342afe0f10aafd00000000801e47f8c184e1","valid":true,"msg":"31363532313030353234","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #80: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"54e76b7683b6650baa6a7fc49b1c51eed9ba9dd463221f7a4f1005a89fe00c59","s":"2ea076886c773eb937ec1cc8374b7915cfd11b1c1ae1166152f2f7806a31c8fd","hash":"8c291e8eeaa45adbaf9aba5c0583462d79cbeb7ac97300000000a37ea6700cda","valid":true,"msg":"35373438303831363936","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #81: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5291deaf24659ffbbce6e3c26f6021097a74abdbb69be4fb10419c0c496c9466","s":"65d6fcf336d27cc7cdb982bb4e4ecef5827f84742f29f10abf83469270a03dc3","hash":"0eaae8641084fa979803efbfb8140732f4cdcf66c3f78a000000003c278a6b21","valid":true,"msg":"36333433393133343638","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #82: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"207a3241812d75d947419dc58efb05e8003b33fc17eb50f9d15166a88479f107","s":"cdee749f2e492b213ce80b32d0574f62f1c5d70793cf55e382d5caadf7592767","hash":"e02716d01fb23a5a0068399bf01bab42ef17c6d96e13846c00000000afc0f89d","valid":true,"msg":"31353431313033353938","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #83: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"6554e49f82a855204328ac94913bf01bbe84437a355a0a37c0dee3cf81aa7728","s":"aea00de2507ddaf5c94e1e126980d3df16250a2eaebc8be486effe7f22b4f929","hash":"9eb0bf583a1a6b9a194e9a16bc7dab2a9061768af89d00659a00000000fc7de1","valid":true,"msg":"3130343738353830313238","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #84: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a54c5062648339d2bff06f71c88216c26c6e19b4d80a8c602990ac82707efdfc","s":"e99bbe7fcfafae3e69fd016777517aa01056317f467ad09aff09be73c9731b0d","hash":"62aac98818b3b84a2c214f0d5e72ef286e1030cb53d9a82b690e00000000cd15","valid":true,"msg":"3130353336323835353638","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #85: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"975bd7157a8d363b309f1f444012b1a1d23096593133e71b4ca8b059cff37eaf","s":"7faa7a28b1c822baa241793f2abc930bd4c69840fe090f2aacc46786bf919622","hash":"3760a7f37cf96218f29ae43732e513efd2b6f552ea4b6895464b9300000000c8","valid":true,"msg":"393533393034313035","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #86: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5694a6f84b8f875c276afd2ebcfe4d61de9ec90305afb1357b95b3e0da43885e","s":"0dffad9ffd0b757d8051dec02ebdf70d8ee2dc5c7870c0823b6ccc7c679cbaa4","hash":"0da0a1d2851d33023834f2098c0880096b4320bea836cd9cbb6ff6c800000000","valid":true,"msg":"393738383438303339","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #87: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a0c30e8026fdb2b4b4968a27d16a6d08f7098f1a98d21620d7454ba9790f1ba6","s":"5e470453a8a399f15baf463f9deceb53acc5ca64459149688bd2760c65424339","hash":"ffffffff293886d3086fd567aafd598f0fe975f735887194a764a231e82d289a","valid":true,"msg":"33363130363732343432","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #88: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"614ea84acf736527dd73602cd4bb4eea1dfebebd5ad8aca52aa0228cf7b99a88","s":"737cc85f5f2d2f60d1b8183f3ed490e4de14368e96a9482c2a4dd193195c902f","hash":"7bffffffff2376d1e3c03445a072e24326acdc4ce127ec2e0e8d9ca99527e7b7","valid":true,"msg":"31303534323430373035","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #89: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bead6734ebe44b810d3fb2ea00b1732945377338febfd439a8d74dfbd0f942fa","s":"6bb18eae36616a7d3cad35919fd21a8af4bbe7a10f73b3e036a46b103ef56e2a","hash":"a2b5ffffffffebb251b085377605a224bc80872602a6e467fd016807e97fa395","valid":true,"msg":"35313734343438313937","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #90: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"499625479e161dacd4db9d9ce64854c98d922cbf212703e9654fae182df9bad2","s":"42c177cf37b8193a0131108d97819edd9439936028864ac195b64fca76d9d693","hash":"641227ffffffff6f1b96fa5f097fcf3cc1a3c256870d45a67b83d0967d4b20c0","valid":true,"msg":"31393637353631323531","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #91: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"08f16b8093a8fb4d66a2c8065b541b3d31e3bfe694f6b89c50fb1aaa6ff6c9b2","s":"9d6455e2d5d1779748573b611cb95d4a21f967410399b39b535ba3e5af81ca2e","hash":"958415d8ffffffffabad03e2fc662dc3ba203521177502298df56f36600e0f8b","valid":true,"msg":"33343437323533333433","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #92: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"be26231b6191658a19dd72ddb99ed8f8c579b6938d19bce8eed8dc2b338cb5f8","s":"e1d9a32ee56cffed37f0f22b2dcb57d5c943c14f79694a03b9c5e96952575c89","hash":"f1d8de4858ffffffff1281093536f47fe13deb04e1fbe8fb954521b6975420f8","valid":true,"msg":"333638323634333138","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #93: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"15e76880898316b16204ac920a02d58045f36a229d4aa4f812638c455abe0443","s":"e74d357d3fcb5c8c5337bd6aba4178b455ca10e226e13f9638196506a1939123","hash":"0927895f2802ffffffff10782dd14a3b32dc5d47c05ef6f1876b95c81fc31def","valid":true,"msg":"33323631313938363038","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #94: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"352ecb53f8df2c503a45f9846fc28d1d31e6307d3ddbffc1132315cc07f16dad","s":"1348dfa9c482c558e1d05c5242ca1c39436726ecd28258b1899792887dd0a3c6","hash":"60907984aa7e8effffffff4f332862a10a57c3063fb5a30624cf6a0c3ac80589","valid":true,"msg":"39363738373831303934","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #95: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"4a40801a7e606ba78a0da9882ab23c7677b8642349ed3d652c5bfa5f2a9558fb","s":"3a49b64848d682ef7f605f2832f7384bdc24ed2925825bf8ea77dc5981725782","hash":"c6ff198484939170ffffffff0af42cda50f9a5f50636ea6942d6b9b8cd6ae1e2","valid":true,"msg":"34393538383233383233","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #96: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"eacc5e1a8304a74d2be412b078924b3bb3511bac855c05c9e5e9e44df3d61e96","s":"7451cd8e18d6ed1885dd827714847f96ec4bb0ed4c36ce9808db8f714204f6d1","hash":"de030419345ca15c75ffffffff8074799b9e0956cc43135d16dfbe4d27d7e68d","valid":true,"msg":"383234363337383337","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #97: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2f7a5e9e5771d424f30f67fdab61e8ce4f8cd1214882adb65f7de94c31577052","s":"ac4e69808345809b44acb0b2bd889175fb75dd050c5a449ab9528f8f78daa10c","hash":"6f0e3eeaf42b28132b88fffffffff6c8665604d34acb19037e1ab78caaaac6ff","valid":true,"msg":"3131303230383333373736","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #98: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffcda40f792ce4d93e7e0f0e95e1a2147dddd7f6487621c30a03d710b3300219","s":"79938b55f8a17f7ed7ba9ade8f2065a1fa77618f0b67add8d58c422c2453a49a","hash":"cdb549f773b3e62b3708d1ffffffffbe48f7c0591ddcae7d2cb222d1f8017ab9","valid":true,"msg":"313333383731363438","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #99: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"81f2359c4faba6b53d3e8c8c3fcc16a948350f7ab3a588b28c17603a431e39a8","s":"cd6f6a5cc3b55ead0ff695d06c6860b509e46d99fccefb9f7f9e101857f74300","hash":"2c3f26f96a3ac0051df4989bffffffff9fd64886c1dc4f9924d8fd6f0edb0484","valid":true,"msg":"333232313434313632","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #100: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"dfc8bf520445cbb8ee1596fb073ea283ea130251a6fdffa5c3f5f2aaf75ca808","s":"048e33efce147c9dd92823640e338e68bfd7d0dc7a4905b3a7ac711e577e90e7","hash":"ac18f8418c55a2502cb7d53f9affffffff5c31d89fda6a6b8476397c04edf411","valid":true,"msg":"3130363836363535353436","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #101: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ad019f74c6941d20efda70b46c53db166503a0e393e932f688227688ba6a5762","s":"93320eb7ca0710255346bdbb3102cdcf7964ef2e0988e712bc05efe16c199345","hash":"4f9618f98e2d3a15b24094f72bb5ffffffffa2fd3e2893683e5a6ab8cf0ee610","valid":true,"msg":"3632313535323436","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #102: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ac8096842e8add68c34e78ce11dd71e4b54316bd3ebf7fffdeb7bd5a3ebc1883","s":"f5ca2f4f23d674502d4caf85d187215d36e3ce9f0ce219709f21a3aac003b7a8","hash":"422e82a3d56ed10a9cc21d31d37a25ffffffff67edf7c40204caae73ab0bc75a","valid":true,"msg":"37303330383138373734","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #103: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"677b2d3a59b18a5ff939b70ea002250889ddcd7b7b9d776854b4943693fb92f7","s":"6b4ba856ade7677bf30307b21f3ccda35d2f63aee81efd0bab6972cc0795db55","hash":"7075d245ccc3281b6e7b329ff738fbb417a5ffffffffa0842d9890b5cf95d018","valid":true,"msg":"35393234353233373434","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #104: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"479e1ded14bcaed0379ba8e1b73d3115d84d31d4b7c30e1f05e1fc0d5957cfb0","s":"918f79e35b3d89487cf634a4f05b2e0c30857ca879f97c771e877027355b2443","hash":"3c80de54cd9226989443d593fa4fd6597e280ebeffffffffc1847eb76c217a95","valid":true,"msg":"31343935353836363231","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #105: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"43dfccd0edb9e280d9a58f01164d55c3d711e14b12ac5cf3b64840ead512a0a3","s":"1dbe33fa8ba84533cd5c4934365b3442ca1174899b78ef9a3199f49584389772","hash":"de21754e29b85601980bef3d697ea2770ce891a8cdffffffffc7906aa794b39b","valid":true,"msg":"34303035333134343036","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #106: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5b09ab637bd4caf0f4c7c7e4bca592fea20e9087c259d26a38bb4085f0bbff11","s":"45b7eb467b6748af618e9d80d6fdcd6aa24964e5a13f885bca8101de08eb0d75","hash":"8f65d92927cfb86a84dd59623fb531bb599e4d5f7289ffffffff2f1f2f57881c","valid":true,"msg":"33303936343537353132","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #107: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5e9b1c5a028070df5728c5c8af9b74e0667afa570a6cfa0114a5039ed15ee06f","s":"b1360907e2d9785ead362bb8d7bd661b6c29eeffd3c5037744edaeb9ad990c20","hash":"6b63e9a74e092120160bea3877dace8a2cc7cd0e8426cbfffffffffafc8c3ca8","valid":true,"msg":"32373834303235363230","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #108: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0671a0a85c2b72d54a2fb0990e34538b4890050f5a5712f6d1a7a5fb8578f32e","s":"db1846bab6b7361479ab9c3285ca41291808f27fd5bd4fdac720e5854713694c","hash":"fc28259702a03845b6d75219444e8b43d094586e249c8699ffffffffe852512e","valid":true,"msg":"32363138373837343138","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #109: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"7673f8526748446477dbbb0590a45492c5d7d69859d301abbaedb35b2095103a","s":"3dc70ddf9c6b524d886bed9e6af02e0e4dec0d417a414fed3807ef4422913d7c","hash":"1273b4502ea4e3bccee044ee8e8db7f774ecbcd52e8ceb571757ffffffffe20a","valid":true,"msg":"31363432363235323632","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #110: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"7f085441070ecd2bb21285089ebb1aa6450d1a06c36d3ff39dfd657a796d12b5","s":"249712012029870a2459d18d47da9aa492a5e6cb4b2d8dafa9e4c5c54a2b9a8b","hash":"08fb565610a79baa0c566c66228d81814f8c53a15b96e602fb49ffffffffff6e","valid":true,"msg":"36383234313839343336","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #111: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"914c67fb61dd1e27c867398ea7322d5ab76df04bc5aa6683a8e0f30a5d287348","s":"fa07474031481dda4953e3ac1959ee8cea7e66ec412b38d6c96d28f6d37304ea","hash":"d59291cc2cf89f3087715fcb1aa4e79aa2403f748e97d7cd28ecaefeffffffff","valid":true,"msg":"343834323435343235","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #112: special case hash"} +{"x":"0ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103","y":"c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e","r":"000000000000000000000000000000004319055358e8617b0c46353d039cdaab","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #113: k*G has a large x-coordinate"} +{"x":"0ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103","y":"c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e","r":"ffffffff00000001000000000000000000000000fffffffffffffffffffffffc","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #114: r too large"} +{"x":"ab05fd9d0de26b9ce6f4819652d9fc69193d0aa398f0fba8013e09c582204554","y":"19235271228c786759095d12b75af0692dd4103f19f6a8c32f49435a1e9b8d45","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #115: r,s are large"} +{"x":"80984f39a1ff38a86a68aa4201b6be5dfbfecf876219710b07badf6fdd4c6c56","y":"11feb97390d9826e7a06dfb41871c940d74415ed3cac2089f1445019bb55ed95","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"909135bdb6799286170f5ead2de4f6511453fe50914f3df2de54a36383df8dd4","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #116: r and s^-1 have a large Hamming weight"} +{"x":"4201b4272944201c3294f5baa9a3232b6dd687495fcc19a70a95bc602b4f7c05","y":"95c37eba9ee8171c1bb5ac6feaf753bc36f463e3aef16629572c0c0a8fb0800e","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"27b4577ca009376f71303fd5dd227dcef5deb773ad5f5a84360644669ca249a5","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #117: r and s^-1 have a large Hamming weight"} +{"x":"a71af64de5126a4a4e02b7922d66ce9415ce88a4c9d25514d91082c8725ac957","y":"5d47723c8fbe580bb369fec9c2665d8e30a435b9932645482e7c9f11e872296b","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #118: small r and s"} +{"x":"6627cec4f0731ea23fc2931f90ebe5b7572f597d20df08fc2b31ee8ef16b1572","y":"6170ed77d8d0a14fc5c9c3c4c9be7f0d3ee18f709bb275eaf2073e258fe694a5","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"0000000000000000000000000000000000000000000000000000000000000003","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #120: small r and s"} +{"x":"5a7c8825e85691cce1f5e7544c54e73f14afc010cb731343262ca7ec5a77f5bf","y":"ef6edf62a4497c1bd7b147fb6c3d22af3c39bfce95f30e13a16d3d7b2812f813","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"0000000000000000000000000000000000000000000000000000000000000005","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #122: small r and s"} +{"x":"cbe0c29132cd738364fedd603152990c048e5e2fff996d883fa6caca7978c737","y":"70af6a8ce44cb41224b2603606f4c04d188e80bff7cc31ad5189d4ab0d70e8c1","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"0000000000000000000000000000000000000000000000000000000000000006","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #124: small r and s"} +{"x":"cbe0c29132cd738364fedd603152990c048e5e2fff996d883fa6caca7978c737","y":"70af6a8ce44cb41224b2603606f4c04d188e80bff7cc31ad5189d4ab0d70e8c1","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632556","s":"0000000000000000000000000000000000000000000000000000000000000006","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #126: r is larger than n"} +{"x":"4be4178097002f0deab68f0d9a130e0ed33a6795d02a20796db83444b037e139","y":"20f13051e0eecdcfce4dacea0f50d1f247caa669f193c1b4075b51ae296d2d56","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc75fbd8","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #127: s is larger than n"} +{"x":"d0f73792203716afd4be4329faa48d269f15313ebbba379d7783c97bf3e890d9","y":"971f4a3206605bec21782bf5e275c714417e8f566549e6bc68690d2363c89cc1","r":"0000000000000000000000000000000000000000000000000000000000000100","s":"8f1e3c7862c58b16bb76eddbb76eddbb516af4f63f2d74d76e0d28c9bb75ea88","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #128: small r and s^-1"} +{"x":"4838b2be35a6276a80ef9e228140f9d9b96ce83b7a254f71ccdebbb8054ce05f","y":"fa9cbc123c919b19e00238198d04069043bd660a828814051fcb8aac738a6c6b","r":"000000000000000000000000000000000000000000000000002d9b4d347952d6","s":"ef3043e7329581dbb3974497710ab11505ee1c87ff907beebadd195a0ffe6d7a","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #129: smallish r and s^-1"} +{"x":"7393983ca30a520bbc4783dc9960746aab444ef520c0a8e771119aa4e74b0f64","y":"e9d7be1ab01a0bf626e709863e6a486dbaf32793afccf774e2c6cd27b1857526","r":"000000000000000000000000000000000000001033e67e37b32b445580bf4eff","s":"8b748b74000000008b748b748b748b7466e769ad4a16d3dcd87129b8e91d1b4d","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #130: 100-bit r and small s^-1"} +{"x":"5ac331a1103fe966697379f356a937f350588a05477e308851b8a502d5dfcdc5","y":"fe9993df4b57939b2b8da095bf6d794265204cfe03be995a02e65d408c871c0b","r":"0000000000000000000000000000000000000000000000000000000000000100","s":"ef9f6ba4d97c09d03178fa20b4aaad83be3cf9cb824a879fec3270fc4b81ef5b","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #131: small r and 100 bit s^-1"} +{"x":"1d209be8de2de877095a399d3904c74cc458d926e27bb8e58e5eae5767c41509","y":"dd59e04c214f7b18dce351fc2a549893a6860e80163f38cc60a4f2c9d040d8c9","r":"00000000000000000000000000000000000000062522bbd3ecbe7c39e93e7c25","s":"ef9f6ba4d97c09d03178fa20b4aaad83be3cf9cb824a879fec3270fc4b81ef5b","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #132: 100-bit r and s^-1"} +{"x":"083539fbee44625e3acaafa2fcb41349392cef0633a1b8fabecee0c133b10e99","y":"915c1ebe7bf00df8535196770a58047ae2a402f26326bb7d41d4d7616337911e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6324d5","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #133: r and s^-1 are close to n"} +{"x":"8aeb368a7027a4d64abdea37390c0c1d6a26f399e2d9734de1eb3d0e19373874","y":"05bd13834715e1dbae9b875cf07bd55e1b6691c7f7536aef3b19bf7a4adf576d","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #134: s == 1"} +{"x":"8aeb368a7027a4d64abdea37390c0c1d6a26f399e2d9734de1eb3d0e19373874","y":"05bd13834715e1dbae9b875cf07bd55e1b6691c7f7536aef3b19bf7a4adf576d","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #135: s == 0"} +{"x":"b533d4695dd5b8c5e07757e55e6e516f7e2c88fa0239e23f60e8ec07dd70f287","y":"1b134ee58cc583278456863f33c3a85d881f7d4a39850143e29d4eaf009afe47","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #136: point at infinity during verify"} +{"x":"f50d371b91bfb1d7d14e1323523bc3aa8cbf2c57f9e284de628c8b4536787b86","y":"f94ad887ac94d527247cd2e7d0c8b1291c553c9730405380b14cbb209f5fa2dd","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","s":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #137: edge case for signature malleability"} +{"x":"68ec6e298eafe16539156ce57a14b04a7047c221bafc3a582eaeb0d857c4d946","y":"97bed1af17850117fdb39b2324f220a5698ed16c426a27335bb385ac8ca6fb30","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","s":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #138: edge case for signature malleability"} +{"x":"69da0364734d2e530fece94019265fefb781a0f1b08f6c8897bdf6557927c8b8","y":"66d2d3c7dcd518b23d726960f069ad71a933d86ef8abbcce8b20f71e2a847002","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #139: u1 == 1"} +{"x":"d8adc00023a8edc02576e2b63e3e30621a471e2b2320620187bf067a1ac1ff32","y":"33e2b50ec09807accb36131fff95ed12a09a86b4ea9690aa32861576ba2362e1","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #140: u1 == n - 1"} +{"x":"3623ac973ced0a56fa6d882f03a7d5c7edca02cfc7b2401fab3690dbe75ab785","y":"8db06908e64b28613da7257e737f39793da8e713ba0643b92e9bb3252be7f8fe","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #141: u2 == 1"} +{"x":"cf04ea77e9622523d894b93ff52dc3027b31959503b6fa3890e5e04263f922f1","y":"e8528fb7c006b3983c8b8400e57b4ed71740c2f3975438821199bedeaecab2e9","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"aaaaaaaa00000000aaaaaaaaaaaaaaaa7def51c91a0fbf034d26872ca84218e1","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #142: u2 == n - 1"} +{"x":"db7a2c8a1ab573e5929dc24077b508d7e683d49227996bda3e9f78dbeff77350","y":"4f417f3bc9a88075c2e0aadd5a13311730cf7cc76a82f11a36eaf08a6c99a206","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"e91e1ba60fdedb76a46bcb51dc0b8b4b7e019f0a28721885fa5d3a8196623397","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #143: edge case for u1"} +{"x":"dead11c7a5b396862f21974dc4752fadeff994efe9bbd05ab413765ea80b6e1f","y":"1de3f0640e8ac6edcf89cff53c40e265bb94078a343736df07aa0318fc7fe1ff","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"fdea5843ffeb73af94313ba4831b53fe24f799e525b1e8e8c87b59b95b430ad9","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #144: edge case for u1"} +{"x":"d0bc472e0d7c81ebaed3a6ef96c18613bb1fea6f994326fbe80e00dfde67c7e9","y":"986c723ea4843d48389b946f64ad56c83ad70ff17ba85335667d1bb9fa619efd","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"03ffcabf2f1b4d2a65190db1680d62bb994e41c5251cd73b3c3dfc5e5bafc035","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #145: edge case for u1"} +{"x":"a0a44ca947d66a2acb736008b9c08d1ab2ad03776e02640f78495d458dd51c32","y":"6337fe5cf8c4604b1f1c409dc2d872d4294a4762420df43a30a2392e40426add","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"4dfbc401f971cd304b33dfdb17d0fed0fe4c1a88ae648e0d2847f74977534989","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #146: edge case for u1"} +{"x":"c9c2115290d008b45fb65fad0f602389298c25420b775019d42b62c3ce8a96b7","y":"3877d25a8080dc02d987ca730f0405c2c9dbefac46f9e601cc3f06e9713973fd","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bc4024761cd2ffd43dfdb17d0fed112b988977055cd3a8e54971eba9cda5ca71","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #147: edge case for u1"} +{"x":"5eca1ef4c287dddc66b8bccf1b88e8a24c0018962f3c5e7efa83bc1a5ff6033e","y":"5e79c4cb2c245b8c45abdce8a8e4da758d92a607c32cd407ecaef22f1c934a71","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"788048ed39a5ffa77bfb62fa1fda2257742bf35d128fb3459f2a0c909ee86f91","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #148: edge case for u1"} +{"x":"5caaa030e7fdf0e4936bc7ab5a96353e0a01e4130c3f8bf22d473e317029a47a","y":"deb6adc462f7058f2a20d371e9702254e9b201642005b3ceda926b42b178bef9","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"476d9131fd381bd917d0fed112bc9e0a5924b5ed5b11167edd8b23582b3cb15e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #149: edge case for u1"} +{"x":"c2fd20bac06e555bb8ac0ce69eb1ea20f83a1fc3501c8a66469b1a31f619b098","y":"6237050779f52b615bd7b8d76a25fc95ca2ed32525c75f27ffc87ac397e6cbaf","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"8374253e3e21bd154448d0a8f640fe46fafa8b19ce78d538f6cc0a19662d3601","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #150: edge case for u1"} +{"x":"3fd6a1ca7f77fb3b0bbe726c372010068426e11ea6ae78ce17bedae4bba86ced","y":"03ce5516406bf8cfaab8745eac1cd69018ad6f50b5461872ddfc56e0db3c8ff4","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"357cfd3be4d01d413c5b9ede36cba5452c11ee7fe14879e749ae6a2d897a52d6","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #151: edge case for u1"} +{"x":"9cb8e51e27a5ae3b624a60d6dc32734e4989db20e9bca3ede1edf7b086911114","y":"b4c104ab3c677e4b36d6556e8ad5f523410a19f2e277aa895fc57322b4427544","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"29798c5c0ee287d4a5e8e6b799fd86b8df5225298e6ffc807cd2f2bc27a0a6d8","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #152: edge case for u1"} +{"x":"a3e52c156dcaf10502620b7955bc2b40bc78ef3d569e1223c262512d8f49602a","y":"4a2039f31c1097024ad3cc86e57321de032355463486164cf192944977df147f","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"0b70f22c781092452dca1a5711fa3a5a1f72add1bf52c2ff7cae4820b30078dd","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #153: edge case for u1"} +{"x":"f19b78928720d5bee8e670fb90010fb15c37bf91b58a5157c3f3c059b2655e88","y":"cf701ec962fb4a11dcf273f5dc357e58468560c7cfeb942d074abd4329260509","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"16e1e458f021248a5b9434ae23f474b43ee55ba37ea585fef95c90416600f1ba","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #154: edge case for u1"} +{"x":"83a744459ecdfb01a5cf52b27a05bb7337482d242f235d7b4cb89345545c90a8","y":"c05d49337b9649813287de9ffe90355fd905df5f3c32945828121f37cc50de6e","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"2252d6856831b6cf895e4f0535eeaf0e5e5809753df848fe760ad86219016a97","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #155: edge case for u1"} +{"x":"dd13c6b34c56982ddae124f039dfd23f4b19bbe88cee8e528ae51e5d6f3a21d7","y":"bfad4c2e6f263fe5eb59ca974d039fc0e4c3345692fb5320bdae4bd3b42a45ff","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"81ffe55f178da695b28c86d8b406b15dab1a9e39661a3ae017fbe390ac0972c3","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #156: edge case for u1"} +{"x":"67e6f659cdde869a2f65f094e94e5b4dfad636bbf95192feeed01b0f3deb7460","y":"a37e0a51f258b7aeb51dfe592f5cfd5685bbe58712c8d9233c62886437c38ba0","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"7fffffffaaaaaaaaffffffffffffffffe9a2538f37b28a2c513dee40fecbb71a","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #157: edge case for u2"} +{"x":"2eb6412505aec05c6545f029932087e490d05511e8ec1f599617bb367f9ecaaf","y":"805f51efcc4803403f9b1ae0124890f06a43fedcddb31830f6669af292895cb0","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"b62f26b5f2a2b26f6de86d42ad8a13da3ab3cccd0459b201de009e526adf21f2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #158: edge case for u2"} +{"x":"84db645868eab35e3a9fd80e056e2e855435e3a6b68d75a50a854625fe0d7f35","y":"6d2589ac655edc9a11ef3e075eddda9abf92e72171570ef7bf43a2ee39338cfe","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bb1d9ac949dd748cd02bbbe749bd351cd57b38bb61403d700686aa7b4c90851e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #159: edge case for u2"} +{"x":"91b9e47c56278662d75c0983b22ca8ea6aa5059b7a2ff7637eb2975e386ad663","y":"49aa8ff283d0f77c18d6d11dc062165fd13c3c0310679c1408302a16854ecfbd","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"66755a00638cdaec1c732513ca0234ece52545dac11f816e818f725b4f60aaf2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #160: edge case for u2"} +{"x":"f3ec2f13caf04d0192b47fb4c5311fb6d4dc6b0a9e802e5327f7ec5ee8e4834d","y":"f97e3e468b7d0db867d6ecfe81e2b0f9531df87efdb47c1338ac321fefe5a432","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"55a00c9fcdaebb6032513ca0234ecfffe98ebe492fdf02e48ca48e982beb3669","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #161: edge case for u2"} +{"x":"d92b200aefcab6ac7dafd9acaf2fa10b3180235b8f46b4503e4693c670fccc88","y":"5ef2f3aebf5b317475336256768f7c19efb7352d27e4cccadc85b6b8ab922c72","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"ab40193f9b5d76c064a27940469d9fffd31d7c925fbe05c919491d3057d66cd2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #162: edge case for u2"} +{"x":"0a88361eb92ecca2625b38e5f98bbabb96bf179b3d76fc48140a3bcd881523cd","y":"e6bdf56033f84a5054035597375d90866aa2c96b86a41ccf6edebf47298ad489","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"ca0234ebb5fdcb13ca0234ecffffffffcb0dadbbc7f549f8a26b4408d0dc8600","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #163: edge case for u2"} +{"x":"d0fb17ccd8fafe827e0c1afc5d8d80366e2b20e7f14a563a2ba50469d84375e8","y":"68612569d39e2bb9f554355564646de99ac602cc6349cf8c1e236a7de7637d93","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff3ea3677e082b9310572620ae19933a9e65b285598711c77298815ad3","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #164: edge case for u2"} +{"x":"836f33bbc1dc0d3d3abbcef0d91f11e2ac4181076c9af0a22b1e4309d3edb276","y":"9ab443ff6f901e30c773867582997c2bec2b0cb8120d760236f3a95bbe881f75","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"266666663bbbbbbbe6666666666666665b37902e023fab7c8f055d86e5cc41f4","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #165: edge case for u2"} +{"x":"92f99fbe973ed4a299719baee4b432741237034dec8d72ba5103cb33e55feeb8","y":"033dd0e91134c734174889f3ebcf1b7a1ac05767289280ee7a794cebd6e69697","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff36db6db7a492492492492492146c573f4c6dfc8d08a443e258970b09","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #166: edge case for u2"} +{"x":"d35ba58da30197d378e618ec0fa7e2e2d12cffd73ebbb2049d130bba434af09e","y":"ff83986e6875e41ea432b7585a49b3a6c77cbb3c47919f8e82874c794635c1d2","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff2aaaaaab7fffffffffffffffc815d0e60b3e596ecb1ad3a27cfd49c4","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #167: edge case for u2"} +{"x":"8651ce490f1b46d73f3ff475149be29136697334a519d7ddab0725c8d0793224","y":"e11c65bd8ca92dc8bc9ae82911f0b52751ce21dd9003ae60900bd825f590cc28","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"7fffffff55555555ffffffffffffffffd344a71e6f651458a27bdc81fd976e37","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #168: edge case for u2"} +{"x":"6d8e1b12c831a0da8795650ff95f101ed921d9e2f72b15b1cdaca9826b9cfc6d","y":"ef6d63e2bc5c089570394a4bc9f892d5e6c7a6a637b20469a58c106ad486bf37","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"3fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192aa","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #169: edge case for u2"} +{"x":"0ae580bae933b4ef2997cbdbb0922328ca9a410f627a0f7dff24cb4d920e1542","y":"8911e7f8cc365a8a88eb81421a361ccc2b99e309d8dcd9a98ba83c3949d893e3","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"5d8ecd64a4eeba466815ddf3a4de9a8e6abd9c5db0a01eb80343553da648428f","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #170: edge case for u2"} +{"x":"5b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963","y":"838a40f2a36092e9004e92d8d940cf5638550ce672ce8b8d4e15eba5499249e9","r":"6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569","s":"bb726660235793aa9957a61e76e00c2c435109cf9a15dd624d53f4301047856b","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #171: point duplication during verification"} +{"x":"5b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963","y":"7c75bf0c5c9f6d17ffb16d2726bf30a9c7aaf31a8d317472b1ea145ab66db616","r":"6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569","s":"bb726660235793aa9957a61e76e00c2c435109cf9a15dd624d53f4301047856b","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #172: duplication bug"} +{"x":"6adda82b90261b0f319faa0d878665a6b6da497f09c903176222c34acfef72a6","y":"47e6f50dcc40ad5d9b59f7602bb222fad71a41bf5e1f9df4959a364c62e488d9","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #173: point with x-coordinate 0"} +{"x":"dd86d3b5f4a13e8511083b78002081c53ff467f11ebd98a51a633db76665d250","y":"45d5c8200c89f2fa10d849349226d21d8dfaed6ff8d5cb3e1b7e17474ebc18f7","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aa9","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #175: comparison with point at infinity "} +{"x":"4fea55b32cb32aca0c12c4cd0abfb4e64b0f5a516e578c016591a93f5a0fbcc5","y":"d7d3fd10b2be668c547b212f6bb14c88f0fecd38a8a4b2c785ed3be62ce4b280","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #176: extreme value for k and edgecase s"} +{"x":"c6a771527024227792170a6f8eee735bf32b7f98af669ead299802e32d7c3107","y":"bc3b4b5e65ab887bbd343572b3e5619261fe3a073e2ffd78412f726867db589e","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #177: extreme value for k and s^-1"} +{"x":"851c2bbad08e54ec7a9af99f49f03644d6ec6d59b207fec98de85a7d15b956ef","y":"cee9960283045075684b410be8d0f7494b91aa2379f60727319f10ddeb0fe9d6","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #178: extreme value for k and s^-1"} +{"x":"f6417c8a670584e388676949e53da7fc55911ff68318d1bf3061205acb19c48f","y":"8f2b743df34ad0f72674acb7505929784779cd9ac916c3669ead43026ab6d43f","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #179: extreme value for k and s^-1"} +{"x":"501421277be45a5eefec6c639930d636032565af420cf3373f557faa7f8a0643","y":"8673d6cb6076e1cfcdc7dfe7384c8e5cac08d74501f2ae6e89cad195d0aa1371","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"49249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #180: extreme value for k and s^-1"} +{"x":"0d935bf9ffc115a527735f729ca8a4ca23ee01a4894adf0e3415ac84e808bb34","y":"3195a3762fea29ed38912bd9ea6c4fde70c3050893a4375850ce61d82eba33c5","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"16a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #181: extreme value for k"} +{"x":"5e59f50708646be8a589355014308e60b668fb670196206c41e748e64e4dca21","y":"5de37fee5c97bcaf7144d5b459982f52eeeafbdf03aacbafef38e213624a01de","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #182: extreme value for k and edgecase s"} +{"x":"169fb797325843faff2f7a5b5445da9e2fd6226f7ef90ef0bfe924104b02db8e","y":"7bbb8de662c7b9b1cf9b22f7a2e582bd46d581d68878efb2b861b131d8a1d667","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #183: extreme value for k and s^-1"} +{"x":"271cd89c000143096b62d4e9e4ca885aef2f7023d18affdaf8b7b54898148754","y":"0a1c6e954e32108435b55fa385b0f76481a609b9149ccb4b02b2ca47fe8e4da5","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #184: extreme value for k and s^-1"} +{"x":"3d0bc7ed8f09d2cb7ddb46ebc1ed799ab1563a9ab84bf524587a220afe499c12","y":"e22dc3b3c103824a4f378d96adb0a408abf19ce7d68aa6244f78cb216fa3f8df","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #185: extreme value for k and s^-1"} +{"x":"a6c885ade1a4c566f9bb010d066974abb281797fa701288c721bcbd23663a9b7","y":"2e424b690957168d193a6096fc77a2b004a9c7d467e007e1f2058458f98af316","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"49249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #186: extreme value for k and s^-1"} +{"x":"8d3c2c2c3b765ba8289e6ac3812572a25bf75df62d87ab7330c3bdbad9ebfa5c","y":"4c6845442d66935b238578d43aec54f7caa1621d1af241d4632e0b780c423f5d","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"16a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #187: extreme value for k"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5","r":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #188: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5","r":"44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #189: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a","r":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #190: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a","r":"44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #191: testing point duplication"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"b292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a","s":"0177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2","hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","valid":true,"msg":"","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #192: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"530bd6b0c9af2d69ba897f6b5fb59695cfbf33afe66dbadcf5b8d2a2a6538e23","s":"d85e489cb7a161fd55ededcedbf4cc0c0987e3e3f0f242cae934c72caa3f43e9","hash":"dc1921946f4af96a2856e7be399007c9e807bdf4c5332f19f59ec9dd1bb8c7b3","valid":true,"msg":"4d7367","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #193: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"a8ea150cb80125d7381c4c1f1da8e9de2711f9917060406a73d7904519e51388","s":"f3ab9fa68bd47973a73b2d40480c2ba50c22c9d76ec217257288293285449b86","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #194: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"986e65933ef2ed4ee5aada139f52b70539aaf63f00a91f29c69178490d57fb71","s":"3dafedfb8da6189d372308cbf1489bbbdabf0c0217d1c0ff0f701aaa7a694b9c","hash":"de47c9b27eb8d300dbb5f2c353e632c393262cf06340c4fa7f1b40c4cbd36f90","valid":true,"msg":"0000000000000000000000000000000000000000","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #195: pseudorandom signature"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"d434e262a49eab7781e353a3565e482550dd0fd5defa013c7f29745eff3569f1","s":"9b0c0a93f267fb6052fd8077be769c2b98953195d7bc10de844218305c6ba17a","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #196: x-coordinate of the public key has many trailing 0's"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"0fe774355c04d060f76d79fd7a772e421463489221bf0a33add0be9b1979110b","s":"500dcba1c69a8fbd43fa4f57f743ce124ca8b91a1f325f3fac6181175df55737","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #197: x-coordinate of the public key has many trailing 0's"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"bb40bf217bed3fb3950c7d39f03d36dc8e3b2cd79693f125bfd06595ee1135e3","s":"541bf3532351ebb032710bdb6a1bf1bfc89a1e291ac692b3fa4780745bb55677","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #198: x-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"664eb7ee6db84a34df3c86ea31389a5405badd5ca99231ff556d3e75a233e73a","s":"59f3c752e52eca46137642490a51560ce0badc678754b8f72e51a2901426a1bd","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #199: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"4cd0429bbabd2827009d6fcd843d4ce39c3e42e2d1631fd001985a79d1fd8b43","s":"9638bf12dd682f60be7ef1d0e0d98f08b7bca77a1a2b869ae466189d2acdabe3","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #200: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"e56c6ea2d1b017091c44d8b6cb62b9f460e3ce9aed5e5fd41e8added97c56c04","s":"a308ec31f281e955be20b457e463440b4fcf2b80258078207fc1378180f89b55","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #201: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"1158a08d291500b4cabed3346d891eee57c176356a2624fb011f8fbbf3466830","s":"228a8c486a736006e082325b85290c5bc91f378b75d487dda46798c18f285519","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #202: y-coordinate of the public key has many trailing 1's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"b1db9289649f59410ea36b0c0fc8d6aa2687b29176939dd23e0dde56d309fa9d","s":"3e1535e4280559015b0dbd987366dcf43a6d1af5c23c7d584e1c3f48a1251336","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #203: y-coordinate of the public key has many trailing 1's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"b7b16e762286cb96446aa8d4e6e7578b0a341a79f2dd1a220ac6f0ca4e24ed86","s":"ddc60a700a139b04661c547d07bbb0721780146df799ccf55e55234ecb8f12bc","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #204: y-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"d82a7c2717261187c8e00d8df963ff35d796edad36bc6e6bd1c91c670d9105b4","s":"3dcabddaf8fcaa61f4603e7cbac0f3c0351ecd5988efb23f680d07debd139929","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #205: x-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"5eb9c8845de68eb13d5befe719f462d77787802baff30ce96a5cba063254af78","s":"2c026ae9be2e2a5e7ca0ff9bbd92fb6e44972186228ee9a62b87ddbe2ef66fb5","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #206: x-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"96843dd03c22abd2f3b782b170239f90f277921becc117d0404a8e4e36230c28","s":"f2be378f526f74a543f67165976de9ed9a31214eb4d7e6db19e1ede123dd991d","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #207: x-coordinate of the public key has many trailing 1's"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"766456dce1857c906f9996af729339464d27e9d98edc2d0e3b760297067421f6","s":"402385ecadae0d8081dccaf5d19037ec4e55376eced699e93646bfbbf19d0b41","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #208: x-coordinate of the public key is large"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"c605c4b2edeab20419e6518a11b2dbc2b97ed8b07cced0b19c34f777de7b9fd9","s":"edf0f612c5f46e03c719647bc8af1b29b2cde2eda700fb1cff5e159d47326dba","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #209: x-coordinate of the public key is large"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"d48b68e6cabfe03cf6141c9ac54141f210e64485d9929ad7b732bfe3b7eb8a84","s":"feedae50c61bd00e19dc26f9b7e2265e4508c389109ad2f208f0772315b6c941","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #210: x-coordinate of the public key is large"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"b7c81457d4aeb6aa65957098569f0479710ad7f6595d5874c35a93d12a5dd4c7","s":"b7961a0b652878c2d568069a432ca18a1a9199f2ca574dad4b9e3a05c0a1cdb3","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #211: x-coordinate of the public key is small"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"6b01332ddb6edfa9a30a1321d5858e1ee3cf97e263e669f8de5e9652e76ff3f7","s":"5939545fced457309a6a04ace2bd0f70139c8f7d86b02cb1cc58f9e69e96cd5a","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #212: x-coordinate of the public key is small"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"efdb884720eaeadc349f9fc356b6c0344101cd2fd8436b7d0e6a4fb93f106361","s":"f24bee6ad5dc05f7613975473aadf3aacba9e77de7d69b6ce48cb60d8113385d","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #213: x-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"31230428405560dcb88fb5a646836aea9b23a23dd973dcbe8014c87b8b20eb07","s":"0f9344d6e812ce166646747694a41b0aaf97374e19f3c5fb8bd7ae3d9bd0beff","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #214: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"caa797da65b320ab0d5c470cda0b36b294359c7db9841d679174db34c4855743","s":"cf543a62f23e212745391aaf7505f345123d2685ee3b941d3de6d9b36242e5a0","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #215: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"7e5f0ab5d900d3d3d7867657e5d6d36519bc54084536e7d21c336ed800185945","s":"9450c07f201faec94b82dfb322e5ac676688294aad35aa72e727ff0b19b646aa","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #216: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"d7d70c581ae9e3f66dc6a480bf037ae23f8a1e4a2136fe4b03aa69f0ca25b356","s":"89c460f8a5a5c2bbba962c8a3ee833a413e85658e62a59e2af41d9127cc47224","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #217: y-coordinate of the public key is large"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"341c1b9ff3c83dd5e0dfa0bf68bcdf4bb7aa20c625975e5eeee34bb396266b34","s":"72b69f061b750fd5121b22b11366fad549c634e77765a017902a67099e0a4469","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #218: y-coordinate of the public key is large"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"70bebe684cdcb5ca72a42f0d873879359bd1781a591809947628d313a3814f67","s":"aec03aca8f5587a4d535fa31027bbe9cc0e464b1c3577f4c2dcde6b2094798a9","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #219: y-coordinate of the public key is large"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"4cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #1: signature malleability"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #2: Legacy:ASN encoding of s misses leading 0"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #3: valid"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"29a3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #118: modify first byte of integer"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e98","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #120: modify last byte of integer"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b491568475b","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #121: modify last byte of integer"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"00b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #124: truncated integer"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5741946b2a137f59262ee6f5bc91001af27a5e1117a64733950642a3d1e8","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #133: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5740946b2a147f59262ee6f5bc90bd01ed280528b62b3aed5fc93f06f739","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #134: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5741946b2a137f59262ee6f5bc91001af27a5e1117a64733950642a3d1e8","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #137: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f47aa2bbd0a4c384ee1493b1f518ada018ef05465583885980861905228a","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #139: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"4cd60b865d442f5a3c7b11eb6c4e0ae79578ec6353a20bf783ecb4b6ea97b825","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #143: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #177: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #178: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #179: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #180: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #181: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #187: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #188: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #189: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #190: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #191: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #197: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #198: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #199: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #200: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #201: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #207: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #208: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #209: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #210: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #211: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #217: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #218: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #219: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #220: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #221: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"64a1aab5000d0e804f3e2fc02bdee9be8ff312334e2ba16d11547c97711c898e","s":"6af015971cc30be6d1a206d4e013e0997772a2f91d73286ffd683b9bb2cf4f1b","hash":"70239dd877f7c944c422f44dea4ed1a52f2627416faf2f072fa50c772ed6f807","valid":true,"msg":"3639383139","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #230: Edge case for Shamir multiplication"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"16aea964a2f6506d6f78c81c91fc7e8bded7d397738448de1e19a0ec580bf266","s":"252cd762130c6667cfe8b7bc47d27d78391e8e80c578d1cd38c3ff033be928e9","hash":"00000000690ed426ccf17803ebe2bd0884bcd58a1bb5e7477ead3645f356e7a9","valid":true,"msg":"343236343739373234","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #231: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9cc98be2347d469bf476dfc26b9b733df2d26d6ef524af917c665baccb23c882","s":"093496459effe2d8d70727b82462f61d0ec1b7847929d10ea631dacb16b56c32","hash":"7300000000213f2a525c6035725235c2f696ad3ebb5ee47f140697ad25770d91","valid":true,"msg":"37313338363834383931","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #232: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"73b3c90ecd390028058164524dde892703dce3dea0d53fa8093999f07ab8aa43","s":"2f67b0b8e20636695bb7d8bf0a651c802ed25a395387b5f4188c0c4075c88634","hash":"ddf2000000005e0be0635b245f0b97978afd25daadeb3edb4a0161c27fe06045","valid":true,"msg":"3130333539333331363638","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #233: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bfab3098252847b328fadf2f89b95c851a7f0eb390763378f37e90119d5ba3dd","s":"bdd64e234e832b1067c2d058ccb44d978195ccebb65c2aaf1e2da9b8b4987e3b","hash":"67ab1900000000784769c4ecb9e164d6642b8499588b89855be1ec355d0841a0","valid":true,"msg":"33393439343031323135","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #234: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"204a9784074b246d8bf8bf04a4ceb1c1f1c9aaab168b1596d17093c5cd21d2cd","s":"51cce41670636783dc06a759c8847868a406c2506fe17975582fe648d1d88b52","hash":"a2bf09460000000076d7dbeffe125eaf02095dff252ee905e296b6350fc311cf","valid":true,"msg":"31333434323933303739","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #235: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ed66dc34f551ac82f63d4aa4f81fe2cb0031a91d1314f835027bca0f1ceeaa03","s":"99ca123aa09b13cd194a422e18d5fda167623c3f6e5d4d6abb8953d67c0c48c7","hash":"3554e827c700000000e1e75e624a06b3a0a353171160858129e15c544e4f0e65","valid":true,"msg":"33373036323131373132","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #236: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"060b700bef665c68899d44f2356a578d126b062023ccc3c056bf0f60a237012b","s":"8d186c027832965f4fcc78a3366ca95dedbb410cbef3f26d6be5d581c11d3610","hash":"9b6cd3b812610000000026941a0f0bb53255ea4c9fd0cb3426e3a54b9fc6965c","valid":true,"msg":"333433363838373132","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #237: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9f6adfe8d5eb5b2c24d7aa7934b6cf29c93ea76cd313c9132bb0c8e38c96831d","s":"b26a9c9e40e55ee0890c944cf271756c906a33e66b5bd15e051593883b5e9902","hash":"883ae39f50bf0100000000e7561c26fc82a52baa51c71ca877162f93c4ae0186","valid":true,"msg":"31333531353330333730","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #238: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a1af03ca91677b673ad2f33615e56174a1abf6da168cebfa8868f4ba273f16b7","s":"20aa73ffe48afa6435cd258b173d0c2377d69022e7d098d75caf24c8c5e06b1c","hash":"a1ce5d6e5ecaf28b0000000000fa7cd010540f420fb4ff7401fe9fce011d0ba6","valid":true,"msg":"36353533323033313236","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #239: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"fdc70602766f8eed11a6c99a71c973d5659355507b843da6e327a28c11893db9","s":"3df5349688a085b137b1eacf456a9e9e0f6d15ec0078ca60a7f83f2b10d21350","hash":"8ea5f645f373f580930000000038345397330012a8ee836c5494cdffd5ee8054","valid":true,"msg":"31353634333436363033","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #240: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"b516a314f2fce530d6537f6a6c49966c23456f63c643cf8e0dc738f7b876e675","s":"d39ffd033c92b6d717dd536fbc5efdf1967c4bd80954479ba66b0120cd16fff2","hash":"660570d323e9f75fa734000000008792d65ce93eabb7d60d8d9c1bbdcb5ef305","valid":true,"msg":"34343239353339313137","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #241: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"3b2cbf046eac45842ecb7984d475831582717bebb6492fd0a485c101e29ff0a8","s":"4c9b7b47a98b0f82de512bc9313aaf51701099cac5f76e68c8595fc1c1d99258","hash":"d0462673154cce587dde8800000000e98d35f1f45cf9c3bf46ada2de4c568c34","valid":true,"msg":"3130393533323631333531","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #242: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"30c87d35e636f540841f14af54e2f9edd79d0312cfa1ab656c3fb15bfde48dcf","s":"47c15a5a82d24b75c85a692bd6ecafeb71409ede23efd08e0db9abf6340677ed","hash":"bd90640269a7822680cedfef000000000caef15a6171059ab83e7b4418d7278f","valid":true,"msg":"35393837333530303431","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #243: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"38686ff0fda2cef6bc43b58cfe6647b9e2e8176d168dec3c68ff262113760f52","s":"067ec3b651f422669601662167fa8717e976e2db5e6a4cf7c2ddabb3fde9d67d","hash":"33239a52d72f1311512e41222a00000000d2dcceb301c54b4beae8e284788a73","valid":true,"msg":"33343633303036383738","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #244: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"44a3e23bf314f2b344fc25c7f2de8b6af3e17d27f5ee844b225985ab6e2775cf","s":"2d48e223205e98041ddc87be532abed584f0411f5729500493c9cc3f4dd15e86","hash":"b8d64fbcd4a1c10f1365d4e6d95c000000007ee4a21a1cbe1dc84c2d941ffaf1","valid":true,"msg":"39383137333230323837","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #245: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ded5b7ec8e90e7bf11f967a3d95110c41b99db3b5aa8d330eb9d638781688e9","s":"7d5792c53628155e1bfc46fb1a67e3088de049c328ae1f44ec69238a009808f9","hash":"01603d3982bf77d7a3fef3183ed092000000003a227420db4088b20fe0e9d84a","valid":true,"msg":"33323232303431303436","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #246: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bdae7bcb580bf335efd3bc3d31870f923eaccafcd40ec2f605976f15137d8b8f","s":"f6dfa12f19e525270b0106eecfe257499f373a4fb318994f24838122ce7ec3c7","hash":"9ea6994f1e0384c8599aa02e6cf66d9c000000004d89ef50b7e9eb0cfbff7363","valid":true,"msg":"36363636333037313034","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #247: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"50f9c4f0cd6940e162720957ffff513799209b78596956d21ece251c2401f1c6","s":"d7033a0a787d338e889defaaabb106b95a4355e411a59c32aa5167dfab244726","hash":"d03215a8401bcf16693979371a01068a4700000000e2fa5bf692bc670905b18c","valid":true,"msg":"31303335393531383938","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #248: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"f612820687604fa01906066a378d67540982e29575d019aabe90924ead5c860d","s":"3f9367702dd7dd4f75ea98afd20e328a1a99f4857b316525328230ce294b0fef","hash":"307bfaaffb650c889c84bf83f0300e5dc87e000000008408fd5f64b582e3bb14","valid":true,"msg":"31383436353937313935","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #249: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9505e407657d6e8bc93db5da7aa6f5081f61980c1949f56b0f2f507da5782a7a","s":"c60d31904e3669738ffbeccab6c3656c08e0ed5cb92b3cfa5e7f71784f9c5021","hash":"bab5c4f4df540d7b33324d36bb0c157551527c00000000e4af574bb4d54ea6b8","valid":true,"msg":"33313336303436313839","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #250: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bbd16fbbb656b6d0d83e6a7787cd691b08735aed371732723e1c68a40404517d","s":"9d8e35dba96028b7787d91315be675877d2d097be5e8ee34560e3e7fd25c0f00","hash":"d4ba47f6ae28f274e4f58d8036f9c36ec2456f5b00000000c3b869197ef5e15e","valid":true,"msg":"32363633373834323534","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #251: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ec9760122db98fd06ea76848d35a6da442d2ceef7559a30cf57c61e92df327e","s":"7ab271da90859479701fccf86e462ee3393fb6814c27b760c4963625c0a19878","hash":"79fd19c7235ea212f29f1fa00984342afe0f10aafd00000000801e47f8c184e1","valid":true,"msg":"31363532313030353234","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #252: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"54e76b7683b6650baa6a7fc49b1c51eed9ba9dd463221f7a4f1005a89fe00c59","s":"2ea076886c773eb937ec1cc8374b7915cfd11b1c1ae1166152f2f7806a31c8fd","hash":"8c291e8eeaa45adbaf9aba5c0583462d79cbeb7ac97300000000a37ea6700cda","valid":true,"msg":"35373438303831363936","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #253: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5291deaf24659ffbbce6e3c26f6021097a74abdbb69be4fb10419c0c496c9466","s":"65d6fcf336d27cc7cdb982bb4e4ecef5827f84742f29f10abf83469270a03dc3","hash":"0eaae8641084fa979803efbfb8140732f4cdcf66c3f78a000000003c278a6b21","valid":true,"msg":"36333433393133343638","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #254: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"207a3241812d75d947419dc58efb05e8003b33fc17eb50f9d15166a88479f107","s":"cdee749f2e492b213ce80b32d0574f62f1c5d70793cf55e382d5caadf7592767","hash":"e02716d01fb23a5a0068399bf01bab42ef17c6d96e13846c00000000afc0f89d","valid":true,"msg":"31353431313033353938","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #255: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"6554e49f82a855204328ac94913bf01bbe84437a355a0a37c0dee3cf81aa7728","s":"aea00de2507ddaf5c94e1e126980d3df16250a2eaebc8be486effe7f22b4f929","hash":"9eb0bf583a1a6b9a194e9a16bc7dab2a9061768af89d00659a00000000fc7de1","valid":true,"msg":"3130343738353830313238","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #256: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a54c5062648339d2bff06f71c88216c26c6e19b4d80a8c602990ac82707efdfc","s":"e99bbe7fcfafae3e69fd016777517aa01056317f467ad09aff09be73c9731b0d","hash":"62aac98818b3b84a2c214f0d5e72ef286e1030cb53d9a82b690e00000000cd15","valid":true,"msg":"3130353336323835353638","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #257: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"975bd7157a8d363b309f1f444012b1a1d23096593133e71b4ca8b059cff37eaf","s":"7faa7a28b1c822baa241793f2abc930bd4c69840fe090f2aacc46786bf919622","hash":"3760a7f37cf96218f29ae43732e513efd2b6f552ea4b6895464b9300000000c8","valid":true,"msg":"393533393034313035","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #258: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5694a6f84b8f875c276afd2ebcfe4d61de9ec90305afb1357b95b3e0da43885e","s":"0dffad9ffd0b757d8051dec02ebdf70d8ee2dc5c7870c0823b6ccc7c679cbaa4","hash":"0da0a1d2851d33023834f2098c0880096b4320bea836cd9cbb6ff6c800000000","valid":true,"msg":"393738383438303339","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #259: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a0c30e8026fdb2b4b4968a27d16a6d08f7098f1a98d21620d7454ba9790f1ba6","s":"5e470453a8a399f15baf463f9deceb53acc5ca64459149688bd2760c65424339","hash":"ffffffff293886d3086fd567aafd598f0fe975f735887194a764a231e82d289a","valid":true,"msg":"33363130363732343432","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #260: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"614ea84acf736527dd73602cd4bb4eea1dfebebd5ad8aca52aa0228cf7b99a88","s":"737cc85f5f2d2f60d1b8183f3ed490e4de14368e96a9482c2a4dd193195c902f","hash":"7bffffffff2376d1e3c03445a072e24326acdc4ce127ec2e0e8d9ca99527e7b7","valid":true,"msg":"31303534323430373035","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #261: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bead6734ebe44b810d3fb2ea00b1732945377338febfd439a8d74dfbd0f942fa","s":"6bb18eae36616a7d3cad35919fd21a8af4bbe7a10f73b3e036a46b103ef56e2a","hash":"a2b5ffffffffebb251b085377605a224bc80872602a6e467fd016807e97fa395","valid":true,"msg":"35313734343438313937","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #262: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"499625479e161dacd4db9d9ce64854c98d922cbf212703e9654fae182df9bad2","s":"42c177cf37b8193a0131108d97819edd9439936028864ac195b64fca76d9d693","hash":"641227ffffffff6f1b96fa5f097fcf3cc1a3c256870d45a67b83d0967d4b20c0","valid":true,"msg":"31393637353631323531","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #263: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"08f16b8093a8fb4d66a2c8065b541b3d31e3bfe694f6b89c50fb1aaa6ff6c9b2","s":"9d6455e2d5d1779748573b611cb95d4a21f967410399b39b535ba3e5af81ca2e","hash":"958415d8ffffffffabad03e2fc662dc3ba203521177502298df56f36600e0f8b","valid":true,"msg":"33343437323533333433","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #264: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"be26231b6191658a19dd72ddb99ed8f8c579b6938d19bce8eed8dc2b338cb5f8","s":"e1d9a32ee56cffed37f0f22b2dcb57d5c943c14f79694a03b9c5e96952575c89","hash":"f1d8de4858ffffffff1281093536f47fe13deb04e1fbe8fb954521b6975420f8","valid":true,"msg":"333638323634333138","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #265: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"15e76880898316b16204ac920a02d58045f36a229d4aa4f812638c455abe0443","s":"e74d357d3fcb5c8c5337bd6aba4178b455ca10e226e13f9638196506a1939123","hash":"0927895f2802ffffffff10782dd14a3b32dc5d47c05ef6f1876b95c81fc31def","valid":true,"msg":"33323631313938363038","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #266: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"352ecb53f8df2c503a45f9846fc28d1d31e6307d3ddbffc1132315cc07f16dad","s":"1348dfa9c482c558e1d05c5242ca1c39436726ecd28258b1899792887dd0a3c6","hash":"60907984aa7e8effffffff4f332862a10a57c3063fb5a30624cf6a0c3ac80589","valid":true,"msg":"39363738373831303934","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #267: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"4a40801a7e606ba78a0da9882ab23c7677b8642349ed3d652c5bfa5f2a9558fb","s":"3a49b64848d682ef7f605f2832f7384bdc24ed2925825bf8ea77dc5981725782","hash":"c6ff198484939170ffffffff0af42cda50f9a5f50636ea6942d6b9b8cd6ae1e2","valid":true,"msg":"34393538383233383233","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #268: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"eacc5e1a8304a74d2be412b078924b3bb3511bac855c05c9e5e9e44df3d61e96","s":"7451cd8e18d6ed1885dd827714847f96ec4bb0ed4c36ce9808db8f714204f6d1","hash":"de030419345ca15c75ffffffff8074799b9e0956cc43135d16dfbe4d27d7e68d","valid":true,"msg":"383234363337383337","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #269: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2f7a5e9e5771d424f30f67fdab61e8ce4f8cd1214882adb65f7de94c31577052","s":"ac4e69808345809b44acb0b2bd889175fb75dd050c5a449ab9528f8f78daa10c","hash":"6f0e3eeaf42b28132b88fffffffff6c8665604d34acb19037e1ab78caaaac6ff","valid":true,"msg":"3131303230383333373736","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #270: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffcda40f792ce4d93e7e0f0e95e1a2147dddd7f6487621c30a03d710b3300219","s":"79938b55f8a17f7ed7ba9ade8f2065a1fa77618f0b67add8d58c422c2453a49a","hash":"cdb549f773b3e62b3708d1ffffffffbe48f7c0591ddcae7d2cb222d1f8017ab9","valid":true,"msg":"313333383731363438","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #271: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"81f2359c4faba6b53d3e8c8c3fcc16a948350f7ab3a588b28c17603a431e39a8","s":"cd6f6a5cc3b55ead0ff695d06c6860b509e46d99fccefb9f7f9e101857f74300","hash":"2c3f26f96a3ac0051df4989bffffffff9fd64886c1dc4f9924d8fd6f0edb0484","valid":true,"msg":"333232313434313632","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #272: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"dfc8bf520445cbb8ee1596fb073ea283ea130251a6fdffa5c3f5f2aaf75ca808","s":"048e33efce147c9dd92823640e338e68bfd7d0dc7a4905b3a7ac711e577e90e7","hash":"ac18f8418c55a2502cb7d53f9affffffff5c31d89fda6a6b8476397c04edf411","valid":true,"msg":"3130363836363535353436","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #273: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ad019f74c6941d20efda70b46c53db166503a0e393e932f688227688ba6a5762","s":"93320eb7ca0710255346bdbb3102cdcf7964ef2e0988e712bc05efe16c199345","hash":"4f9618f98e2d3a15b24094f72bb5ffffffffa2fd3e2893683e5a6ab8cf0ee610","valid":true,"msg":"3632313535323436","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #274: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ac8096842e8add68c34e78ce11dd71e4b54316bd3ebf7fffdeb7bd5a3ebc1883","s":"f5ca2f4f23d674502d4caf85d187215d36e3ce9f0ce219709f21a3aac003b7a8","hash":"422e82a3d56ed10a9cc21d31d37a25ffffffff67edf7c40204caae73ab0bc75a","valid":true,"msg":"37303330383138373734","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #275: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"677b2d3a59b18a5ff939b70ea002250889ddcd7b7b9d776854b4943693fb92f7","s":"6b4ba856ade7677bf30307b21f3ccda35d2f63aee81efd0bab6972cc0795db55","hash":"7075d245ccc3281b6e7b329ff738fbb417a5ffffffffa0842d9890b5cf95d018","valid":true,"msg":"35393234353233373434","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #276: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"479e1ded14bcaed0379ba8e1b73d3115d84d31d4b7c30e1f05e1fc0d5957cfb0","s":"918f79e35b3d89487cf634a4f05b2e0c30857ca879f97c771e877027355b2443","hash":"3c80de54cd9226989443d593fa4fd6597e280ebeffffffffc1847eb76c217a95","valid":true,"msg":"31343935353836363231","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #277: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"43dfccd0edb9e280d9a58f01164d55c3d711e14b12ac5cf3b64840ead512a0a3","s":"1dbe33fa8ba84533cd5c4934365b3442ca1174899b78ef9a3199f49584389772","hash":"de21754e29b85601980bef3d697ea2770ce891a8cdffffffffc7906aa794b39b","valid":true,"msg":"34303035333134343036","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #278: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5b09ab637bd4caf0f4c7c7e4bca592fea20e9087c259d26a38bb4085f0bbff11","s":"45b7eb467b6748af618e9d80d6fdcd6aa24964e5a13f885bca8101de08eb0d75","hash":"8f65d92927cfb86a84dd59623fb531bb599e4d5f7289ffffffff2f1f2f57881c","valid":true,"msg":"33303936343537353132","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #279: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5e9b1c5a028070df5728c5c8af9b74e0667afa570a6cfa0114a5039ed15ee06f","s":"b1360907e2d9785ead362bb8d7bd661b6c29eeffd3c5037744edaeb9ad990c20","hash":"6b63e9a74e092120160bea3877dace8a2cc7cd0e8426cbfffffffffafc8c3ca8","valid":true,"msg":"32373834303235363230","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #280: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0671a0a85c2b72d54a2fb0990e34538b4890050f5a5712f6d1a7a5fb8578f32e","s":"db1846bab6b7361479ab9c3285ca41291808f27fd5bd4fdac720e5854713694c","hash":"fc28259702a03845b6d75219444e8b43d094586e249c8699ffffffffe852512e","valid":true,"msg":"32363138373837343138","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #281: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"7673f8526748446477dbbb0590a45492c5d7d69859d301abbaedb35b2095103a","s":"3dc70ddf9c6b524d886bed9e6af02e0e4dec0d417a414fed3807ef4422913d7c","hash":"1273b4502ea4e3bccee044ee8e8db7f774ecbcd52e8ceb571757ffffffffe20a","valid":true,"msg":"31363432363235323632","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #282: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"7f085441070ecd2bb21285089ebb1aa6450d1a06c36d3ff39dfd657a796d12b5","s":"249712012029870a2459d18d47da9aa492a5e6cb4b2d8dafa9e4c5c54a2b9a8b","hash":"08fb565610a79baa0c566c66228d81814f8c53a15b96e602fb49ffffffffff6e","valid":true,"msg":"36383234313839343336","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #283: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"914c67fb61dd1e27c867398ea7322d5ab76df04bc5aa6683a8e0f30a5d287348","s":"fa07474031481dda4953e3ac1959ee8cea7e66ec412b38d6c96d28f6d37304ea","hash":"d59291cc2cf89f3087715fcb1aa4e79aa2403f748e97d7cd28ecaefeffffffff","valid":true,"msg":"343834323435343235","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #284: special case hash"} +{"x":"0ad99500288d466940031d72a9f5445a4d43784640855bf0a69874d2de5fe103","y":"c5011e6ef2c42dcd50d5d3d29f99ae6eba2c80c9244f4c5422f0979ff0c3ba5e","r":"ffffffff00000001000000000000000000000000fffffffffffffffffffffffc","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #286: r too large"} +{"x":"ab05fd9d0de26b9ce6f4819652d9fc69193d0aa398f0fba8013e09c582204554","y":"19235271228c786759095d12b75af0692dd4103f19f6a8c32f49435a1e9b8d45","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #287: r,s are large"} +{"x":"80984f39a1ff38a86a68aa4201b6be5dfbfecf876219710b07badf6fdd4c6c56","y":"11feb97390d9826e7a06dfb41871c940d74415ed3cac2089f1445019bb55ed95","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"909135bdb6799286170f5ead2de4f6511453fe50914f3df2de54a36383df8dd4","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #288: r and s^-1 have a large Hamming weight"} +{"x":"4201b4272944201c3294f5baa9a3232b6dd687495fcc19a70a95bc602b4f7c05","y":"95c37eba9ee8171c1bb5ac6feaf753bc36f463e3aef16629572c0c0a8fb0800e","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"27b4577ca009376f71303fd5dd227dcef5deb773ad5f5a84360644669ca249a5","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #289: r and s^-1 have a large Hamming weight"} +{"x":"083539fbee44625e3acaafa2fcb41349392cef0633a1b8fabecee0c133b10e99","y":"915c1ebe7bf00df8535196770a58047ae2a402f26326bb7d41d4d7616337911e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6324d5","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #301: r and s^-1 are close to n"} +{"x":"b533d4695dd5b8c5e07757e55e6e516f7e2c88fa0239e23f60e8ec07dd70f287","y":"1b134ee58cc583278456863f33c3a85d881f7d4a39850143e29d4eaf009afe47","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #304: point at infinity during verify"} +{"x":"f50d371b91bfb1d7d14e1323523bc3aa8cbf2c57f9e284de628c8b4536787b86","y":"f94ad887ac94d527247cd2e7d0c8b1291c553c9730405380b14cbb209f5fa2dd","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","s":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #305: edge case for signature malleability"} +{"x":"68ec6e298eafe16539156ce57a14b04a7047c221bafc3a582eaeb0d857c4d946","y":"97bed1af17850117fdb39b2324f220a5698ed16c426a27335bb385ac8ca6fb30","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","s":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #306: edge case for signature malleability"} +{"x":"69da0364734d2e530fece94019265fefb781a0f1b08f6c8897bdf6557927c8b8","y":"66d2d3c7dcd518b23d726960f069ad71a933d86ef8abbcce8b20f71e2a847002","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #307: u1 == 1"} +{"x":"d8adc00023a8edc02576e2b63e3e30621a471e2b2320620187bf067a1ac1ff32","y":"33e2b50ec09807accb36131fff95ed12a09a86b4ea9690aa32861576ba2362e1","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #308: u1 == n - 1"} +{"x":"3623ac973ced0a56fa6d882f03a7d5c7edca02cfc7b2401fab3690dbe75ab785","y":"8db06908e64b28613da7257e737f39793da8e713ba0643b92e9bb3252be7f8fe","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #309: u2 == 1"} +{"x":"cf04ea77e9622523d894b93ff52dc3027b31959503b6fa3890e5e04263f922f1","y":"e8528fb7c006b3983c8b8400e57b4ed71740c2f3975438821199bedeaecab2e9","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"aaaaaaaa00000000aaaaaaaaaaaaaaaa7def51c91a0fbf034d26872ca84218e1","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #310: u2 == n - 1"} +{"x":"db7a2c8a1ab573e5929dc24077b508d7e683d49227996bda3e9f78dbeff77350","y":"4f417f3bc9a88075c2e0aadd5a13311730cf7cc76a82f11a36eaf08a6c99a206","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"e91e1ba60fdedb76a46bcb51dc0b8b4b7e019f0a28721885fa5d3a8196623397","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #311: edge case for u1"} +{"x":"dead11c7a5b396862f21974dc4752fadeff994efe9bbd05ab413765ea80b6e1f","y":"1de3f0640e8ac6edcf89cff53c40e265bb94078a343736df07aa0318fc7fe1ff","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"fdea5843ffeb73af94313ba4831b53fe24f799e525b1e8e8c87b59b95b430ad9","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #312: edge case for u1"} +{"x":"d0bc472e0d7c81ebaed3a6ef96c18613bb1fea6f994326fbe80e00dfde67c7e9","y":"986c723ea4843d48389b946f64ad56c83ad70ff17ba85335667d1bb9fa619efd","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"03ffcabf2f1b4d2a65190db1680d62bb994e41c5251cd73b3c3dfc5e5bafc035","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #313: edge case for u1"} +{"x":"a0a44ca947d66a2acb736008b9c08d1ab2ad03776e02640f78495d458dd51c32","y":"6337fe5cf8c4604b1f1c409dc2d872d4294a4762420df43a30a2392e40426add","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"4dfbc401f971cd304b33dfdb17d0fed0fe4c1a88ae648e0d2847f74977534989","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #314: edge case for u1"} +{"x":"c9c2115290d008b45fb65fad0f602389298c25420b775019d42b62c3ce8a96b7","y":"3877d25a8080dc02d987ca730f0405c2c9dbefac46f9e601cc3f06e9713973fd","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bc4024761cd2ffd43dfdb17d0fed112b988977055cd3a8e54971eba9cda5ca71","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #315: edge case for u1"} +{"x":"5eca1ef4c287dddc66b8bccf1b88e8a24c0018962f3c5e7efa83bc1a5ff6033e","y":"5e79c4cb2c245b8c45abdce8a8e4da758d92a607c32cd407ecaef22f1c934a71","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"788048ed39a5ffa77bfb62fa1fda2257742bf35d128fb3459f2a0c909ee86f91","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #316: edge case for u1"} +{"x":"5caaa030e7fdf0e4936bc7ab5a96353e0a01e4130c3f8bf22d473e317029a47a","y":"deb6adc462f7058f2a20d371e9702254e9b201642005b3ceda926b42b178bef9","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"476d9131fd381bd917d0fed112bc9e0a5924b5ed5b11167edd8b23582b3cb15e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #317: edge case for u1"} +{"x":"c2fd20bac06e555bb8ac0ce69eb1ea20f83a1fc3501c8a66469b1a31f619b098","y":"6237050779f52b615bd7b8d76a25fc95ca2ed32525c75f27ffc87ac397e6cbaf","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"8374253e3e21bd154448d0a8f640fe46fafa8b19ce78d538f6cc0a19662d3601","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #318: edge case for u1"} +{"x":"3fd6a1ca7f77fb3b0bbe726c372010068426e11ea6ae78ce17bedae4bba86ced","y":"03ce5516406bf8cfaab8745eac1cd69018ad6f50b5461872ddfc56e0db3c8ff4","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"357cfd3be4d01d413c5b9ede36cba5452c11ee7fe14879e749ae6a2d897a52d6","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #319: edge case for u1"} +{"x":"9cb8e51e27a5ae3b624a60d6dc32734e4989db20e9bca3ede1edf7b086911114","y":"b4c104ab3c677e4b36d6556e8ad5f523410a19f2e277aa895fc57322b4427544","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"29798c5c0ee287d4a5e8e6b799fd86b8df5225298e6ffc807cd2f2bc27a0a6d8","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #320: edge case for u1"} +{"x":"a3e52c156dcaf10502620b7955bc2b40bc78ef3d569e1223c262512d8f49602a","y":"4a2039f31c1097024ad3cc86e57321de032355463486164cf192944977df147f","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"0b70f22c781092452dca1a5711fa3a5a1f72add1bf52c2ff7cae4820b30078dd","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #321: edge case for u1"} +{"x":"f19b78928720d5bee8e670fb90010fb15c37bf91b58a5157c3f3c059b2655e88","y":"cf701ec962fb4a11dcf273f5dc357e58468560c7cfeb942d074abd4329260509","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"16e1e458f021248a5b9434ae23f474b43ee55ba37ea585fef95c90416600f1ba","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #322: edge case for u1"} +{"x":"83a744459ecdfb01a5cf52b27a05bb7337482d242f235d7b4cb89345545c90a8","y":"c05d49337b9649813287de9ffe90355fd905df5f3c32945828121f37cc50de6e","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"2252d6856831b6cf895e4f0535eeaf0e5e5809753df848fe760ad86219016a97","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #323: edge case for u1"} +{"x":"dd13c6b34c56982ddae124f039dfd23f4b19bbe88cee8e528ae51e5d6f3a21d7","y":"bfad4c2e6f263fe5eb59ca974d039fc0e4c3345692fb5320bdae4bd3b42a45ff","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"81ffe55f178da695b28c86d8b406b15dab1a9e39661a3ae017fbe390ac0972c3","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #324: edge case for u1"} +{"x":"67e6f659cdde869a2f65f094e94e5b4dfad636bbf95192feeed01b0f3deb7460","y":"a37e0a51f258b7aeb51dfe592f5cfd5685bbe58712c8d9233c62886437c38ba0","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"7fffffffaaaaaaaaffffffffffffffffe9a2538f37b28a2c513dee40fecbb71a","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #325: edge case for u2"} +{"x":"2eb6412505aec05c6545f029932087e490d05511e8ec1f599617bb367f9ecaaf","y":"805f51efcc4803403f9b1ae0124890f06a43fedcddb31830f6669af292895cb0","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"b62f26b5f2a2b26f6de86d42ad8a13da3ab3cccd0459b201de009e526adf21f2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #326: edge case for u2"} +{"x":"84db645868eab35e3a9fd80e056e2e855435e3a6b68d75a50a854625fe0d7f35","y":"6d2589ac655edc9a11ef3e075eddda9abf92e72171570ef7bf43a2ee39338cfe","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bb1d9ac949dd748cd02bbbe749bd351cd57b38bb61403d700686aa7b4c90851e","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #327: edge case for u2"} +{"x":"91b9e47c56278662d75c0983b22ca8ea6aa5059b7a2ff7637eb2975e386ad663","y":"49aa8ff283d0f77c18d6d11dc062165fd13c3c0310679c1408302a16854ecfbd","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"66755a00638cdaec1c732513ca0234ece52545dac11f816e818f725b4f60aaf2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #328: edge case for u2"} +{"x":"f3ec2f13caf04d0192b47fb4c5311fb6d4dc6b0a9e802e5327f7ec5ee8e4834d","y":"f97e3e468b7d0db867d6ecfe81e2b0f9531df87efdb47c1338ac321fefe5a432","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"55a00c9fcdaebb6032513ca0234ecfffe98ebe492fdf02e48ca48e982beb3669","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #329: edge case for u2"} +{"x":"d92b200aefcab6ac7dafd9acaf2fa10b3180235b8f46b4503e4693c670fccc88","y":"5ef2f3aebf5b317475336256768f7c19efb7352d27e4cccadc85b6b8ab922c72","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"ab40193f9b5d76c064a27940469d9fffd31d7c925fbe05c919491d3057d66cd2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #330: edge case for u2"} +{"x":"0a88361eb92ecca2625b38e5f98bbabb96bf179b3d76fc48140a3bcd881523cd","y":"e6bdf56033f84a5054035597375d90866aa2c96b86a41ccf6edebf47298ad489","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"ca0234ebb5fdcb13ca0234ecffffffffcb0dadbbc7f549f8a26b4408d0dc8600","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #331: edge case for u2"} +{"x":"d0fb17ccd8fafe827e0c1afc5d8d80366e2b20e7f14a563a2ba50469d84375e8","y":"68612569d39e2bb9f554355564646de99ac602cc6349cf8c1e236a7de7637d93","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff3ea3677e082b9310572620ae19933a9e65b285598711c77298815ad3","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #332: edge case for u2"} +{"x":"836f33bbc1dc0d3d3abbcef0d91f11e2ac4181076c9af0a22b1e4309d3edb276","y":"9ab443ff6f901e30c773867582997c2bec2b0cb8120d760236f3a95bbe881f75","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"266666663bbbbbbbe6666666666666665b37902e023fab7c8f055d86e5cc41f4","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #333: edge case for u2"} +{"x":"92f99fbe973ed4a299719baee4b432741237034dec8d72ba5103cb33e55feeb8","y":"033dd0e91134c734174889f3ebcf1b7a1ac05767289280ee7a794cebd6e69697","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff36db6db7a492492492492492146c573f4c6dfc8d08a443e258970b09","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #334: edge case for u2"} +{"x":"d35ba58da30197d378e618ec0fa7e2e2d12cffd73ebbb2049d130bba434af09e","y":"ff83986e6875e41ea432b7585a49b3a6c77cbb3c47919f8e82874c794635c1d2","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff2aaaaaab7fffffffffffffffc815d0e60b3e596ecb1ad3a27cfd49c4","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #335: edge case for u2"} +{"x":"8651ce490f1b46d73f3ff475149be29136697334a519d7ddab0725c8d0793224","y":"e11c65bd8ca92dc8bc9ae82911f0b52751ce21dd9003ae60900bd825f590cc28","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"7fffffff55555555ffffffffffffffffd344a71e6f651458a27bdc81fd976e37","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #336: edge case for u2"} +{"x":"6d8e1b12c831a0da8795650ff95f101ed921d9e2f72b15b1cdaca9826b9cfc6d","y":"ef6d63e2bc5c089570394a4bc9f892d5e6c7a6a637b20469a58c106ad486bf37","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"3fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192aa","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #337: edge case for u2"} +{"x":"0ae580bae933b4ef2997cbdbb0922328ca9a410f627a0f7dff24cb4d920e1542","y":"8911e7f8cc365a8a88eb81421a361ccc2b99e309d8dcd9a98ba83c3949d893e3","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"5d8ecd64a4eeba466815ddf3a4de9a8e6abd9c5db0a01eb80343553da648428f","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #338: edge case for u2"} +{"x":"5b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963","y":"838a40f2a36092e9004e92d8d940cf5638550ce672ce8b8d4e15eba5499249e9","r":"6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569","s":"bb726660235793aa9957a61e76e00c2c435109cf9a15dd624d53f4301047856b","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #339: point duplication during verification"} +{"x":"5b812fd521aafa69835a849cce6fbdeb6983b442d2444fe70e134c027fc46963","y":"7c75bf0c5c9f6d17ffb16d2726bf30a9c7aaf31a8d317472b1ea145ab66db616","r":"6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569","s":"bb726660235793aa9957a61e76e00c2c435109cf9a15dd624d53f4301047856b","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #340: duplication bug"} +{"x":"dd86d3b5f4a13e8511083b78002081c53ff467f11ebd98a51a633db76665d250","y":"45d5c8200c89f2fa10d849349226d21d8dfaed6ff8d5cb3e1b7e17474ebc18f7","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aa9","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #343: comparison with point at infinity "} +{"x":"4fea55b32cb32aca0c12c4cd0abfb4e64b0f5a516e578c016591a93f5a0fbcc5","y":"d7d3fd10b2be668c547b212f6bb14c88f0fecd38a8a4b2c785ed3be62ce4b280","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #344: extreme value for k and edgecase s"} +{"x":"c6a771527024227792170a6f8eee735bf32b7f98af669ead299802e32d7c3107","y":"bc3b4b5e65ab887bbd343572b3e5619261fe3a073e2ffd78412f726867db589e","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #345: extreme value for k and s^-1"} +{"x":"851c2bbad08e54ec7a9af99f49f03644d6ec6d59b207fec98de85a7d15b956ef","y":"cee9960283045075684b410be8d0f7494b91aa2379f60727319f10ddeb0fe9d6","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #346: extreme value for k and s^-1"} +{"x":"f6417c8a670584e388676949e53da7fc55911ff68318d1bf3061205acb19c48f","y":"8f2b743df34ad0f72674acb7505929784779cd9ac916c3669ead43026ab6d43f","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #347: extreme value for k and s^-1"} +{"x":"501421277be45a5eefec6c639930d636032565af420cf3373f557faa7f8a0643","y":"8673d6cb6076e1cfcdc7dfe7384c8e5cac08d74501f2ae6e89cad195d0aa1371","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"49249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #348: extreme value for k and s^-1"} +{"x":"0d935bf9ffc115a527735f729ca8a4ca23ee01a4894adf0e3415ac84e808bb34","y":"3195a3762fea29ed38912bd9ea6c4fde70c3050893a4375850ce61d82eba33c5","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"16a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #349: extreme value for k"} +{"x":"5e59f50708646be8a589355014308e60b668fb670196206c41e748e64e4dca21","y":"5de37fee5c97bcaf7144d5b459982f52eeeafbdf03aacbafef38e213624a01de","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #350: extreme value for k and edgecase s"} +{"x":"169fb797325843faff2f7a5b5445da9e2fd6226f7ef90ef0bfe924104b02db8e","y":"7bbb8de662c7b9b1cf9b22f7a2e582bd46d581d68878efb2b861b131d8a1d667","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #351: extreme value for k and s^-1"} +{"x":"271cd89c000143096b62d4e9e4ca885aef2f7023d18affdaf8b7b54898148754","y":"0a1c6e954e32108435b55fa385b0f76481a609b9149ccb4b02b2ca47fe8e4da5","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #352: extreme value for k and s^-1"} +{"x":"3d0bc7ed8f09d2cb7ddb46ebc1ed799ab1563a9ab84bf524587a220afe499c12","y":"e22dc3b3c103824a4f378d96adb0a408abf19ce7d68aa6244f78cb216fa3f8df","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #353: extreme value for k and s^-1"} +{"x":"a6c885ade1a4c566f9bb010d066974abb281797fa701288c721bcbd23663a9b7","y":"2e424b690957168d193a6096fc77a2b004a9c7d467e007e1f2058458f98af316","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"49249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #354: extreme value for k and s^-1"} +{"x":"8d3c2c2c3b765ba8289e6ac3812572a25bf75df62d87ab7330c3bdbad9ebfa5c","y":"4c6845442d66935b238578d43aec54f7caa1621d1af241d4632e0b780c423f5d","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"16a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #355: extreme value for k"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5","r":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #356: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5","r":"44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #357: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a","r":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #358: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a","r":"44a5ad0ad0636d9f12bc9e0a6bdd5e1cbcb012ea7bf091fcec15b0c43202d52e","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #359: testing point duplication"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"b292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a","s":"0177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2","hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","valid":true,"msg":"","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #360: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"530bd6b0c9af2d69ba897f6b5fb59695cfbf33afe66dbadcf5b8d2a2a6538e23","s":"d85e489cb7a161fd55ededcedbf4cc0c0987e3e3f0f242cae934c72caa3f43e9","hash":"dc1921946f4af96a2856e7be399007c9e807bdf4c5332f19f59ec9dd1bb8c7b3","valid":true,"msg":"4d7367","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #361: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"a8ea150cb80125d7381c4c1f1da8e9de2711f9917060406a73d7904519e51388","s":"f3ab9fa68bd47973a73b2d40480c2ba50c22c9d76ec217257288293285449b86","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #362: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"986e65933ef2ed4ee5aada139f52b70539aaf63f00a91f29c69178490d57fb71","s":"3dafedfb8da6189d372308cbf1489bbbdabf0c0217d1c0ff0f701aaa7a694b9c","hash":"de47c9b27eb8d300dbb5f2c353e632c393262cf06340c4fa7f1b40c4cbd36f90","valid":true,"msg":"0000000000000000000000000000000000000000","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #363: pseudorandom signature"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"d434e262a49eab7781e353a3565e482550dd0fd5defa013c7f29745eff3569f1","s":"9b0c0a93f267fb6052fd8077be769c2b98953195d7bc10de844218305c6ba17a","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #364: x-coordinate of the public key has many trailing 0's"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"0fe774355c04d060f76d79fd7a772e421463489221bf0a33add0be9b1979110b","s":"500dcba1c69a8fbd43fa4f57f743ce124ca8b91a1f325f3fac6181175df55737","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #365: x-coordinate of the public key has many trailing 0's"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"bb40bf217bed3fb3950c7d39f03d36dc8e3b2cd79693f125bfd06595ee1135e3","s":"541bf3532351ebb032710bdb6a1bf1bfc89a1e291ac692b3fa4780745bb55677","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #366: x-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"664eb7ee6db84a34df3c86ea31389a5405badd5ca99231ff556d3e75a233e73a","s":"59f3c752e52eca46137642490a51560ce0badc678754b8f72e51a2901426a1bd","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #367: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"4cd0429bbabd2827009d6fcd843d4ce39c3e42e2d1631fd001985a79d1fd8b43","s":"9638bf12dd682f60be7ef1d0e0d98f08b7bca77a1a2b869ae466189d2acdabe3","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #368: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"e56c6ea2d1b017091c44d8b6cb62b9f460e3ce9aed5e5fd41e8added97c56c04","s":"a308ec31f281e955be20b457e463440b4fcf2b80258078207fc1378180f89b55","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #369: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"1158a08d291500b4cabed3346d891eee57c176356a2624fb011f8fbbf3466830","s":"228a8c486a736006e082325b85290c5bc91f378b75d487dda46798c18f285519","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #370: y-coordinate of the public key has many trailing 1's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"b1db9289649f59410ea36b0c0fc8d6aa2687b29176939dd23e0dde56d309fa9d","s":"3e1535e4280559015b0dbd987366dcf43a6d1af5c23c7d584e1c3f48a1251336","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #371: y-coordinate of the public key has many trailing 1's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"b7b16e762286cb96446aa8d4e6e7578b0a341a79f2dd1a220ac6f0ca4e24ed86","s":"ddc60a700a139b04661c547d07bbb0721780146df799ccf55e55234ecb8f12bc","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #372: y-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"d82a7c2717261187c8e00d8df963ff35d796edad36bc6e6bd1c91c670d9105b4","s":"3dcabddaf8fcaa61f4603e7cbac0f3c0351ecd5988efb23f680d07debd139929","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #373: x-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"5eb9c8845de68eb13d5befe719f462d77787802baff30ce96a5cba063254af78","s":"2c026ae9be2e2a5e7ca0ff9bbd92fb6e44972186228ee9a62b87ddbe2ef66fb5","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #374: x-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"96843dd03c22abd2f3b782b170239f90f277921becc117d0404a8e4e36230c28","s":"f2be378f526f74a543f67165976de9ed9a31214eb4d7e6db19e1ede123dd991d","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #375: x-coordinate of the public key has many trailing 1's"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"766456dce1857c906f9996af729339464d27e9d98edc2d0e3b760297067421f6","s":"402385ecadae0d8081dccaf5d19037ec4e55376eced699e93646bfbbf19d0b41","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #376: x-coordinate of the public key is large"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"c605c4b2edeab20419e6518a11b2dbc2b97ed8b07cced0b19c34f777de7b9fd9","s":"edf0f612c5f46e03c719647bc8af1b29b2cde2eda700fb1cff5e159d47326dba","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #377: x-coordinate of the public key is large"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"d48b68e6cabfe03cf6141c9ac54141f210e64485d9929ad7b732bfe3b7eb8a84","s":"feedae50c61bd00e19dc26f9b7e2265e4508c389109ad2f208f0772315b6c941","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #378: x-coordinate of the public key is large"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"b7c81457d4aeb6aa65957098569f0479710ad7f6595d5874c35a93d12a5dd4c7","s":"b7961a0b652878c2d568069a432ca18a1a9199f2ca574dad4b9e3a05c0a1cdb3","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #379: x-coordinate of the public key is small"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"6b01332ddb6edfa9a30a1321d5858e1ee3cf97e263e669f8de5e9652e76ff3f7","s":"5939545fced457309a6a04ace2bd0f70139c8f7d86b02cb1cc58f9e69e96cd5a","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #380: x-coordinate of the public key is small"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"efdb884720eaeadc349f9fc356b6c0344101cd2fd8436b7d0e6a4fb93f106361","s":"f24bee6ad5dc05f7613975473aadf3aacba9e77de7d69b6ce48cb60d8113385d","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #381: x-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"31230428405560dcb88fb5a646836aea9b23a23dd973dcbe8014c87b8b20eb07","s":"0f9344d6e812ce166646747694a41b0aaf97374e19f3c5fb8bd7ae3d9bd0beff","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #382: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"caa797da65b320ab0d5c470cda0b36b294359c7db9841d679174db34c4855743","s":"cf543a62f23e212745391aaf7505f345123d2685ee3b941d3de6d9b36242e5a0","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #383: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"7e5f0ab5d900d3d3d7867657e5d6d36519bc54084536e7d21c336ed800185945","s":"9450c07f201faec94b82dfb322e5ac676688294aad35aa72e727ff0b19b646aa","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #384: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"d7d70c581ae9e3f66dc6a480bf037ae23f8a1e4a2136fe4b03aa69f0ca25b356","s":"89c460f8a5a5c2bbba962c8a3ee833a413e85658e62a59e2af41d9127cc47224","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #385: y-coordinate of the public key is large"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"341c1b9ff3c83dd5e0dfa0bf68bcdf4bb7aa20c625975e5eeee34bb396266b34","s":"72b69f061b750fd5121b22b11366fad549c634e77765a017902a67099e0a4469","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #386: y-coordinate of the public key is large"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"70bebe684cdcb5ca72a42f0d873879359bd1781a591809947628d313a3814f67","s":"aec03aca8f5587a4d535fa31027bbe9cc0e464b1c3577f4c2dcde6b2094798a9","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #387: y-coordinate of the public key is large"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"4cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1: signature malleability"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #2: Legacy:ASN encoding of s misses leading 0"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #3: valid"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"29a3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #118: modify first byte of integer"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e98","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #120: modify last byte of integer"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b491568475b","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #121: modify last byte of integer"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"00b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #124: truncated integer"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5741946b2a137f59262ee6f5bc91001af27a5e1117a64733950642a3d1e8","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #133: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5740946b2a147f59262ee6f5bc90bd01ed280528b62b3aed5fc93f06f739","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #134: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5741946b2a137f59262ee6f5bc91001af27a5e1117a64733950642a3d1e8","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #137: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"b329f47aa2bbd0a4c384ee1493b1f518ada018ef05465583885980861905228a","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #139: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"4cd60b865d442f5a3c7b11eb6c4e0ae79578ec6353a20bf783ecb4b6ea97b825","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #143: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #177: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #178: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #179: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #180: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #181: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #187: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #188: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #189: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #190: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #191: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #197: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #198: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #199: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #200: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #201: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #207: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #208: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #209: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #210: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #211: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #217: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #218: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #219: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #220: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #221: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"64a1aab5000d0e804f3e2fc02bdee9be8ff312334e2ba16d11547c97711c898e","s":"6af015971cc30be6d1a206d4e013e0997772a2f91d73286ffd683b9bb2cf4f1b","hash":"70239dd877f7c944c422f44dea4ed1a52f2627416faf2f072fa50c772ed6f807","valid":true,"msg":"3639383139","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #230: Edge case for Shamir multiplication"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"16aea964a2f6506d6f78c81c91fc7e8bded7d397738448de1e19a0ec580bf266","s":"252cd762130c6667cfe8b7bc47d27d78391e8e80c578d1cd38c3ff033be928e9","hash":"00000000690ed426ccf17803ebe2bd0884bcd58a1bb5e7477ead3645f356e7a9","valid":true,"msg":"343236343739373234","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #231: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9cc98be2347d469bf476dfc26b9b733df2d26d6ef524af917c665baccb23c882","s":"093496459effe2d8d70727b82462f61d0ec1b7847929d10ea631dacb16b56c32","hash":"7300000000213f2a525c6035725235c2f696ad3ebb5ee47f140697ad25770d91","valid":true,"msg":"37313338363834383931","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #232: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"73b3c90ecd390028058164524dde892703dce3dea0d53fa8093999f07ab8aa43","s":"2f67b0b8e20636695bb7d8bf0a651c802ed25a395387b5f4188c0c4075c88634","hash":"ddf2000000005e0be0635b245f0b97978afd25daadeb3edb4a0161c27fe06045","valid":true,"msg":"3130333539333331363638","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #233: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bfab3098252847b328fadf2f89b95c851a7f0eb390763378f37e90119d5ba3dd","s":"bdd64e234e832b1067c2d058ccb44d978195ccebb65c2aaf1e2da9b8b4987e3b","hash":"67ab1900000000784769c4ecb9e164d6642b8499588b89855be1ec355d0841a0","valid":true,"msg":"33393439343031323135","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #234: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"204a9784074b246d8bf8bf04a4ceb1c1f1c9aaab168b1596d17093c5cd21d2cd","s":"51cce41670636783dc06a759c8847868a406c2506fe17975582fe648d1d88b52","hash":"a2bf09460000000076d7dbeffe125eaf02095dff252ee905e296b6350fc311cf","valid":true,"msg":"31333434323933303739","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #235: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ed66dc34f551ac82f63d4aa4f81fe2cb0031a91d1314f835027bca0f1ceeaa03","s":"99ca123aa09b13cd194a422e18d5fda167623c3f6e5d4d6abb8953d67c0c48c7","hash":"3554e827c700000000e1e75e624a06b3a0a353171160858129e15c544e4f0e65","valid":true,"msg":"33373036323131373132","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #236: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"060b700bef665c68899d44f2356a578d126b062023ccc3c056bf0f60a237012b","s":"8d186c027832965f4fcc78a3366ca95dedbb410cbef3f26d6be5d581c11d3610","hash":"9b6cd3b812610000000026941a0f0bb53255ea4c9fd0cb3426e3a54b9fc6965c","valid":true,"msg":"333433363838373132","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #237: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9f6adfe8d5eb5b2c24d7aa7934b6cf29c93ea76cd313c9132bb0c8e38c96831d","s":"b26a9c9e40e55ee0890c944cf271756c906a33e66b5bd15e051593883b5e9902","hash":"883ae39f50bf0100000000e7561c26fc82a52baa51c71ca877162f93c4ae0186","valid":true,"msg":"31333531353330333730","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #238: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a1af03ca91677b673ad2f33615e56174a1abf6da168cebfa8868f4ba273f16b7","s":"20aa73ffe48afa6435cd258b173d0c2377d69022e7d098d75caf24c8c5e06b1c","hash":"a1ce5d6e5ecaf28b0000000000fa7cd010540f420fb4ff7401fe9fce011d0ba6","valid":true,"msg":"36353533323033313236","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #239: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"fdc70602766f8eed11a6c99a71c973d5659355507b843da6e327a28c11893db9","s":"3df5349688a085b137b1eacf456a9e9e0f6d15ec0078ca60a7f83f2b10d21350","hash":"8ea5f645f373f580930000000038345397330012a8ee836c5494cdffd5ee8054","valid":true,"msg":"31353634333436363033","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #240: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"b516a314f2fce530d6537f6a6c49966c23456f63c643cf8e0dc738f7b876e675","s":"d39ffd033c92b6d717dd536fbc5efdf1967c4bd80954479ba66b0120cd16fff2","hash":"660570d323e9f75fa734000000008792d65ce93eabb7d60d8d9c1bbdcb5ef305","valid":true,"msg":"34343239353339313137","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #241: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"3b2cbf046eac45842ecb7984d475831582717bebb6492fd0a485c101e29ff0a8","s":"4c9b7b47a98b0f82de512bc9313aaf51701099cac5f76e68c8595fc1c1d99258","hash":"d0462673154cce587dde8800000000e98d35f1f45cf9c3bf46ada2de4c568c34","valid":true,"msg":"3130393533323631333531","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #242: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"30c87d35e636f540841f14af54e2f9edd79d0312cfa1ab656c3fb15bfde48dcf","s":"47c15a5a82d24b75c85a692bd6ecafeb71409ede23efd08e0db9abf6340677ed","hash":"bd90640269a7822680cedfef000000000caef15a6171059ab83e7b4418d7278f","valid":true,"msg":"35393837333530303431","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #243: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"38686ff0fda2cef6bc43b58cfe6647b9e2e8176d168dec3c68ff262113760f52","s":"067ec3b651f422669601662167fa8717e976e2db5e6a4cf7c2ddabb3fde9d67d","hash":"33239a52d72f1311512e41222a00000000d2dcceb301c54b4beae8e284788a73","valid":true,"msg":"33343633303036383738","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #244: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"44a3e23bf314f2b344fc25c7f2de8b6af3e17d27f5ee844b225985ab6e2775cf","s":"2d48e223205e98041ddc87be532abed584f0411f5729500493c9cc3f4dd15e86","hash":"b8d64fbcd4a1c10f1365d4e6d95c000000007ee4a21a1cbe1dc84c2d941ffaf1","valid":true,"msg":"39383137333230323837","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #245: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ded5b7ec8e90e7bf11f967a3d95110c41b99db3b5aa8d330eb9d638781688e9","s":"7d5792c53628155e1bfc46fb1a67e3088de049c328ae1f44ec69238a009808f9","hash":"01603d3982bf77d7a3fef3183ed092000000003a227420db4088b20fe0e9d84a","valid":true,"msg":"33323232303431303436","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #246: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bdae7bcb580bf335efd3bc3d31870f923eaccafcd40ec2f605976f15137d8b8f","s":"f6dfa12f19e525270b0106eecfe257499f373a4fb318994f24838122ce7ec3c7","hash":"9ea6994f1e0384c8599aa02e6cf66d9c000000004d89ef50b7e9eb0cfbff7363","valid":true,"msg":"36363636333037313034","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #247: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"50f9c4f0cd6940e162720957ffff513799209b78596956d21ece251c2401f1c6","s":"d7033a0a787d338e889defaaabb106b95a4355e411a59c32aa5167dfab244726","hash":"d03215a8401bcf16693979371a01068a4700000000e2fa5bf692bc670905b18c","valid":true,"msg":"31303335393531383938","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #248: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"f612820687604fa01906066a378d67540982e29575d019aabe90924ead5c860d","s":"3f9367702dd7dd4f75ea98afd20e328a1a99f4857b316525328230ce294b0fef","hash":"307bfaaffb650c889c84bf83f0300e5dc87e000000008408fd5f64b582e3bb14","valid":true,"msg":"31383436353937313935","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #249: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9505e407657d6e8bc93db5da7aa6f5081f61980c1949f56b0f2f507da5782a7a","s":"c60d31904e3669738ffbeccab6c3656c08e0ed5cb92b3cfa5e7f71784f9c5021","hash":"bab5c4f4df540d7b33324d36bb0c157551527c00000000e4af574bb4d54ea6b8","valid":true,"msg":"33313336303436313839","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #250: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bbd16fbbb656b6d0d83e6a7787cd691b08735aed371732723e1c68a40404517d","s":"9d8e35dba96028b7787d91315be675877d2d097be5e8ee34560e3e7fd25c0f00","hash":"d4ba47f6ae28f274e4f58d8036f9c36ec2456f5b00000000c3b869197ef5e15e","valid":true,"msg":"32363633373834323534","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #251: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ec9760122db98fd06ea76848d35a6da442d2ceef7559a30cf57c61e92df327e","s":"7ab271da90859479701fccf86e462ee3393fb6814c27b760c4963625c0a19878","hash":"79fd19c7235ea212f29f1fa00984342afe0f10aafd00000000801e47f8c184e1","valid":true,"msg":"31363532313030353234","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #252: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"54e76b7683b6650baa6a7fc49b1c51eed9ba9dd463221f7a4f1005a89fe00c59","s":"2ea076886c773eb937ec1cc8374b7915cfd11b1c1ae1166152f2f7806a31c8fd","hash":"8c291e8eeaa45adbaf9aba5c0583462d79cbeb7ac97300000000a37ea6700cda","valid":true,"msg":"35373438303831363936","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #253: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5291deaf24659ffbbce6e3c26f6021097a74abdbb69be4fb10419c0c496c9466","s":"65d6fcf336d27cc7cdb982bb4e4ecef5827f84742f29f10abf83469270a03dc3","hash":"0eaae8641084fa979803efbfb8140732f4cdcf66c3f78a000000003c278a6b21","valid":true,"msg":"36333433393133343638","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #254: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"207a3241812d75d947419dc58efb05e8003b33fc17eb50f9d15166a88479f107","s":"cdee749f2e492b213ce80b32d0574f62f1c5d70793cf55e382d5caadf7592767","hash":"e02716d01fb23a5a0068399bf01bab42ef17c6d96e13846c00000000afc0f89d","valid":true,"msg":"31353431313033353938","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #255: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"6554e49f82a855204328ac94913bf01bbe84437a355a0a37c0dee3cf81aa7728","s":"aea00de2507ddaf5c94e1e126980d3df16250a2eaebc8be486effe7f22b4f929","hash":"9eb0bf583a1a6b9a194e9a16bc7dab2a9061768af89d00659a00000000fc7de1","valid":true,"msg":"3130343738353830313238","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #256: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a54c5062648339d2bff06f71c88216c26c6e19b4d80a8c602990ac82707efdfc","s":"e99bbe7fcfafae3e69fd016777517aa01056317f467ad09aff09be73c9731b0d","hash":"62aac98818b3b84a2c214f0d5e72ef286e1030cb53d9a82b690e00000000cd15","valid":true,"msg":"3130353336323835353638","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #257: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"975bd7157a8d363b309f1f444012b1a1d23096593133e71b4ca8b059cff37eaf","s":"7faa7a28b1c822baa241793f2abc930bd4c69840fe090f2aacc46786bf919622","hash":"3760a7f37cf96218f29ae43732e513efd2b6f552ea4b6895464b9300000000c8","valid":true,"msg":"393533393034313035","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #258: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5694a6f84b8f875c276afd2ebcfe4d61de9ec90305afb1357b95b3e0da43885e","s":"0dffad9ffd0b757d8051dec02ebdf70d8ee2dc5c7870c0823b6ccc7c679cbaa4","hash":"0da0a1d2851d33023834f2098c0880096b4320bea836cd9cbb6ff6c800000000","valid":true,"msg":"393738383438303339","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #259: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a0c30e8026fdb2b4b4968a27d16a6d08f7098f1a98d21620d7454ba9790f1ba6","s":"5e470453a8a399f15baf463f9deceb53acc5ca64459149688bd2760c65424339","hash":"ffffffff293886d3086fd567aafd598f0fe975f735887194a764a231e82d289a","valid":true,"msg":"33363130363732343432","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #260: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"614ea84acf736527dd73602cd4bb4eea1dfebebd5ad8aca52aa0228cf7b99a88","s":"737cc85f5f2d2f60d1b8183f3ed490e4de14368e96a9482c2a4dd193195c902f","hash":"7bffffffff2376d1e3c03445a072e24326acdc4ce127ec2e0e8d9ca99527e7b7","valid":true,"msg":"31303534323430373035","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #261: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bead6734ebe44b810d3fb2ea00b1732945377338febfd439a8d74dfbd0f942fa","s":"6bb18eae36616a7d3cad35919fd21a8af4bbe7a10f73b3e036a46b103ef56e2a","hash":"a2b5ffffffffebb251b085377605a224bc80872602a6e467fd016807e97fa395","valid":true,"msg":"35313734343438313937","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #262: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"499625479e161dacd4db9d9ce64854c98d922cbf212703e9654fae182df9bad2","s":"42c177cf37b8193a0131108d97819edd9439936028864ac195b64fca76d9d693","hash":"641227ffffffff6f1b96fa5f097fcf3cc1a3c256870d45a67b83d0967d4b20c0","valid":true,"msg":"31393637353631323531","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #263: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"08f16b8093a8fb4d66a2c8065b541b3d31e3bfe694f6b89c50fb1aaa6ff6c9b2","s":"9d6455e2d5d1779748573b611cb95d4a21f967410399b39b535ba3e5af81ca2e","hash":"958415d8ffffffffabad03e2fc662dc3ba203521177502298df56f36600e0f8b","valid":true,"msg":"33343437323533333433","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #264: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"be26231b6191658a19dd72ddb99ed8f8c579b6938d19bce8eed8dc2b338cb5f8","s":"e1d9a32ee56cffed37f0f22b2dcb57d5c943c14f79694a03b9c5e96952575c89","hash":"f1d8de4858ffffffff1281093536f47fe13deb04e1fbe8fb954521b6975420f8","valid":true,"msg":"333638323634333138","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #265: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"15e76880898316b16204ac920a02d58045f36a229d4aa4f812638c455abe0443","s":"e74d357d3fcb5c8c5337bd6aba4178b455ca10e226e13f9638196506a1939123","hash":"0927895f2802ffffffff10782dd14a3b32dc5d47c05ef6f1876b95c81fc31def","valid":true,"msg":"33323631313938363038","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #266: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"352ecb53f8df2c503a45f9846fc28d1d31e6307d3ddbffc1132315cc07f16dad","s":"1348dfa9c482c558e1d05c5242ca1c39436726ecd28258b1899792887dd0a3c6","hash":"60907984aa7e8effffffff4f332862a10a57c3063fb5a30624cf6a0c3ac80589","valid":true,"msg":"39363738373831303934","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #267: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"4a40801a7e606ba78a0da9882ab23c7677b8642349ed3d652c5bfa5f2a9558fb","s":"3a49b64848d682ef7f605f2832f7384bdc24ed2925825bf8ea77dc5981725782","hash":"c6ff198484939170ffffffff0af42cda50f9a5f50636ea6942d6b9b8cd6ae1e2","valid":true,"msg":"34393538383233383233","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #268: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"eacc5e1a8304a74d2be412b078924b3bb3511bac855c05c9e5e9e44df3d61e96","s":"7451cd8e18d6ed1885dd827714847f96ec4bb0ed4c36ce9808db8f714204f6d1","hash":"de030419345ca15c75ffffffff8074799b9e0956cc43135d16dfbe4d27d7e68d","valid":true,"msg":"383234363337383337","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #269: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2f7a5e9e5771d424f30f67fdab61e8ce4f8cd1214882adb65f7de94c31577052","s":"ac4e69808345809b44acb0b2bd889175fb75dd050c5a449ab9528f8f78daa10c","hash":"6f0e3eeaf42b28132b88fffffffff6c8665604d34acb19037e1ab78caaaac6ff","valid":true,"msg":"3131303230383333373736","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #270: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffcda40f792ce4d93e7e0f0e95e1a2147dddd7f6487621c30a03d710b3300219","s":"79938b55f8a17f7ed7ba9ade8f2065a1fa77618f0b67add8d58c422c2453a49a","hash":"cdb549f773b3e62b3708d1ffffffffbe48f7c0591ddcae7d2cb222d1f8017ab9","valid":true,"msg":"313333383731363438","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #271: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"81f2359c4faba6b53d3e8c8c3fcc16a948350f7ab3a588b28c17603a431e39a8","s":"cd6f6a5cc3b55ead0ff695d06c6860b509e46d99fccefb9f7f9e101857f74300","hash":"2c3f26f96a3ac0051df4989bffffffff9fd64886c1dc4f9924d8fd6f0edb0484","valid":true,"msg":"333232313434313632","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #272: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"dfc8bf520445cbb8ee1596fb073ea283ea130251a6fdffa5c3f5f2aaf75ca808","s":"048e33efce147c9dd92823640e338e68bfd7d0dc7a4905b3a7ac711e577e90e7","hash":"ac18f8418c55a2502cb7d53f9affffffff5c31d89fda6a6b8476397c04edf411","valid":true,"msg":"3130363836363535353436","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #273: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ad019f74c6941d20efda70b46c53db166503a0e393e932f688227688ba6a5762","s":"93320eb7ca0710255346bdbb3102cdcf7964ef2e0988e712bc05efe16c199345","hash":"4f9618f98e2d3a15b24094f72bb5ffffffffa2fd3e2893683e5a6ab8cf0ee610","valid":true,"msg":"3632313535323436","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #274: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ac8096842e8add68c34e78ce11dd71e4b54316bd3ebf7fffdeb7bd5a3ebc1883","s":"f5ca2f4f23d674502d4caf85d187215d36e3ce9f0ce219709f21a3aac003b7a8","hash":"422e82a3d56ed10a9cc21d31d37a25ffffffff67edf7c40204caae73ab0bc75a","valid":true,"msg":"37303330383138373734","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #275: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"677b2d3a59b18a5ff939b70ea002250889ddcd7b7b9d776854b4943693fb92f7","s":"6b4ba856ade7677bf30307b21f3ccda35d2f63aee81efd0bab6972cc0795db55","hash":"7075d245ccc3281b6e7b329ff738fbb417a5ffffffffa0842d9890b5cf95d018","valid":true,"msg":"35393234353233373434","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #276: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"479e1ded14bcaed0379ba8e1b73d3115d84d31d4b7c30e1f05e1fc0d5957cfb0","s":"918f79e35b3d89487cf634a4f05b2e0c30857ca879f97c771e877027355b2443","hash":"3c80de54cd9226989443d593fa4fd6597e280ebeffffffffc1847eb76c217a95","valid":true,"msg":"31343935353836363231","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #277: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"43dfccd0edb9e280d9a58f01164d55c3d711e14b12ac5cf3b64840ead512a0a3","s":"1dbe33fa8ba84533cd5c4934365b3442ca1174899b78ef9a3199f49584389772","hash":"de21754e29b85601980bef3d697ea2770ce891a8cdffffffffc7906aa794b39b","valid":true,"msg":"34303035333134343036","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #278: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5b09ab637bd4caf0f4c7c7e4bca592fea20e9087c259d26a38bb4085f0bbff11","s":"45b7eb467b6748af618e9d80d6fdcd6aa24964e5a13f885bca8101de08eb0d75","hash":"8f65d92927cfb86a84dd59623fb531bb599e4d5f7289ffffffff2f1f2f57881c","valid":true,"msg":"33303936343537353132","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #279: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5e9b1c5a028070df5728c5c8af9b74e0667afa570a6cfa0114a5039ed15ee06f","s":"b1360907e2d9785ead362bb8d7bd661b6c29eeffd3c5037744edaeb9ad990c20","hash":"6b63e9a74e092120160bea3877dace8a2cc7cd0e8426cbfffffffffafc8c3ca8","valid":true,"msg":"32373834303235363230","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #280: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0671a0a85c2b72d54a2fb0990e34538b4890050f5a5712f6d1a7a5fb8578f32e","s":"db1846bab6b7361479ab9c3285ca41291808f27fd5bd4fdac720e5854713694c","hash":"fc28259702a03845b6d75219444e8b43d094586e249c8699ffffffffe852512e","valid":true,"msg":"32363138373837343138","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #281: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"7673f8526748446477dbbb0590a45492c5d7d69859d301abbaedb35b2095103a","s":"3dc70ddf9c6b524d886bed9e6af02e0e4dec0d417a414fed3807ef4422913d7c","hash":"1273b4502ea4e3bccee044ee8e8db7f774ecbcd52e8ceb571757ffffffffe20a","valid":true,"msg":"31363432363235323632","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #282: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"7f085441070ecd2bb21285089ebb1aa6450d1a06c36d3ff39dfd657a796d12b5","s":"249712012029870a2459d18d47da9aa492a5e6cb4b2d8dafa9e4c5c54a2b9a8b","hash":"08fb565610a79baa0c566c66228d81814f8c53a15b96e602fb49ffffffffff6e","valid":true,"msg":"36383234313839343336","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #283: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"914c67fb61dd1e27c867398ea7322d5ab76df04bc5aa6683a8e0f30a5d287348","s":"fa07474031481dda4953e3ac1959ee8cea7e66ec412b38d6c96d28f6d37304ea","hash":"d59291cc2cf89f3087715fcb1aa4e79aa2403f748e97d7cd28ecaefeffffffff","valid":true,"msg":"343834323435343235","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #284: special case hash"} +{"x":"d705d16f80987e2d9b1a6957d29ce22febf7d10fa515153182415c8361baaca4","y":"b1fc105ee5ce80d514ec1238beae2037a6f83625593620d460819e8682160926","r":"ffffffff00000001000000000000000000000000fffffffffffffffffffffffc","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #636: r too large"} +{"x":"3cd8d2f81d6953b0844c09d7b560d527cd2ef67056893eadafa52c8501387d59","y":"ee41fdb4d10402ce7a0c5e3b747adfa3a490b62a6b7719068903485c0bb6dc2d","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #637: r,s are large"} +{"x":"8240cd81edd91cb6936133508c3915100e81f332c4545d41189b481196851378","y":"e05b06e72d4a1bff80ea5db514aa2f93ea6dd6d9c0ae27b7837dc432f9ce89d9","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"909135bdb6799286170f5ead2de4f6511453fe50914f3df2de54a36383df8dd4","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #638: r and s^-1 have a large Hamming weight"} +{"x":"b062947356748b0fc17f1704c65aa1dca6e1bfe6779756fa616d91eaad13df2c","y":"0b38c17f3d0672e7409cfc5992a99fff12b84a4f8432293b431113f1b2fb579d","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"27b4577ca009376f71303fd5dd227dcef5deb773ad5f5a84360644669ca249a5","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #639: r and s^-1 have a large Hamming weight"} +{"x":"7a736d8e326a9ca62bbe25a34ea4e3633b499a96afa7aaa3fcf3fd88f8e07ede","y":"b3e45879d8622b93e818443a686e869eeda7bf9ae46aa3eafcc48a5934864627","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6324d5","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #651: r and s^-1 are close to n"} +{"x":"0203736fcb198b15d8d7a0c80f66dddd15259240aa78d08aae67c467de045034","y":"34383438d5041ea9a387ee8e4d4e84b4471b160c6bcf2568b072f8f20e87a996","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #654: point at infinity during verify"} +{"x":"78d844dc7f16b73b1f2a39730da5d8cd99fe2e70a18482384e37dcd2bfea02e1","y":"ed6572e01eb7a8d113d02c666c45ef22d3b9a6a6dea99aa43a8183c26e75d336","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","s":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #655: edge case for signature malleability"} +{"x":"dec6c8257dde94110eacc8c09d2e5789cc5beb81a958b02b4d62da9599a74014","y":"66fae1614174be63970b83f6524421067b06dd6f4e9c56baca4e344fdd690f1d","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","s":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #656: edge case for signature malleability"} +{"x":"a17f5b75a35ed64623ca5cbf1f91951292db0c23f0c2ea24c3d0cad0988cabc0","y":"83a7a618625c228940730b4fa3ee64faecbb2fc20fdde7c58b3a3f6300424dc6","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #657: u1 == 1"} +{"x":"04ba0cba291a37db13f33bf90dab628c04ec8393a0200419e9eaa1ebcc9fb5c3","y":"1f3a0a0e6823a49b625ad57b12a32d4047970fc3428f0f0049ecf4265dc12f62","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"acd155416a8b77f34089464733ff7cd39c400e9c69af7beb9eac5054ed2ec72c","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #658: u1 == n - 1"} +{"x":"692b6c828e0feed63d8aeaa2b7322f9ccbe8723a1ed39f229f204a434b8900ef","y":"a1f6f6abcb38ea3b8fde38b98c7c271f274af56a8c5628dc3329069ae4dd5716","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #659: u2 == 1"} +{"x":"00cefd9162d13e64cb93687a9cd8f9755ebb5a3ef7632f800f84871874ccef09","y":"543ecbeaf7e8044ef721be2fb5f549e4b8480d2587404ebf7dbbef2c54bc0cb1","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"aaaaaaaa00000000aaaaaaaaaaaaaaaa7def51c91a0fbf034d26872ca84218e1","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #660: u2 == n - 1"} +{"x":"b975183b42551cf52f291d5c1921fd5e12f50c8c85a4beb9de03efa3f0f24486","y":"2243018e6866df922dc313612020311ff21e242ce3fb15bc78c406b25ab43091","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"710f8e3edc7c2d5a3fd23de844002bb949d9f794f6d5405f6d97c1bb03dd2bd2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #661: edge case for u1"} +{"x":"c25f1d166f3e211cdf042a26f8abf6094d48b8d17191d74ed717149274466999","y":"65d06dd6a88abfa49e8b4c5da6bb922851969adf9604b5accfb52a114e77ccdb","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"edffbc270f722c243069a7e5f40335a61a58525c7b4db2e7a8e269274ffe4e1b","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #662: edge case for u1"} +{"x":"8fe5e88243a76e41a004236218a3c3a2d6eee398a23c3a0b008d7f0164cbc0ca","y":"98a20d1bdcf573513c7cfd9b83c63e3a82d40127c897697c86b8cb387af7f240","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"a25adcae105ed7ff4f95d2344e24ee523314c3e178525d007904b68919ba4d53","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #663: edge case for u1"} +{"x":"02148256b530fbc470c7b341970b38243ecee6d5a840a37beca2efb37e8dff2c","y":"c0adbea0882482a7489ca703a399864ba987eeb6ddb738af53a83573473cb30d","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"2e4348c645707dce6760d773de3f3e87346924b2f64bd3dd0297e766b5805ebb","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #664: edge case for u1"} +{"x":"a34db012ce6eda1e9c7375c5fcf3e54ed698e19615124273b3a621d021c76f8e","y":"777458d6f55a364c221e39e1205d5510bb4fbb7ddf08d8d8fdde13d1d6df7f14","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"348c673b07dce3920d773de3f3e87408869e916dbcf797d8f9684fb67753d1dc","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #665: edge case for u1"} +{"x":"b97af3fe78be15f2912b6271dd8a43badb6dd2a1b315b2ce7ae37b4e7778041d","y":"930d71ee1992d2466495c42102d08e81154c305307d1dcd52d0fa4c479b278e7","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"6918ce760fb9c7241aee7bc7e7d0e8110d3d22db79ef2fb1f2d09f6ceea7a3b8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #666: edge case for u1"} +{"x":"81e7198a3c3f23901cedc7a1d6eff6e9bf81108e6c35cd8559139af3135dbcbb","y":"9ef1568530291a8061b90c9f4285eefcba990d4570a4e3b7b737525b5d580034","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"73b3c694391d8eadde3f3e874089464715ac20e4c126bbf6d864d648969f5b5a","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #667: edge case for u1"} +{"x":"ab4d792ca121d1dba39cb9de645149c2ab573e8becc6ddff3cc9960f188ddf73","y":"7f90ba23664153e93262ff73355415195858d7be1315a69456386de68285a3c8","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bb07ac7a86948c2c2989a16db1930ef1b89ce112595197656877e53c41457f28","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #668: edge case for u1"} +{"x":"518412b69af43aae084476a68d59bbde51fbfa9e5be80563f587c9c2652f88ef","y":"2d3b90d25baa6bdb7b0c55e5240a3a98fbc24afed8523edec1c70503fc10f233","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"27e4d82cb6c061dd9337c69bf9332ed3d198662d6f2299443f62c861187db648","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #669: edge case for u1"} +{"x":"a08f14a644b9a935dffea4761ebaf592d1f66fe6cd373aa7f5d370af34f8352d","y":"a54b5bc4025cf335900a914c2934ec2fec7a396d0a7affcad732a5741c7aaaf5","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"e7c5cf3aac2e88923b77850515fff6a12d13b356dfe9ec275c3dd81ae94609a4","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #670: edge case for u1"} +{"x":"ccf2296a6a89b62b90739d38af4ae3a20e9f45715b90044639241061e33f8f8c","y":"aace0046491eeaa1c6e9a472b96d88f4af83e7ff1bb84438c7e058034412ae08","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"c77838df91c1e953e016e10bddffea2317f9fee32bacfe553cede9e57a748f68","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #671: edge case for u1"} +{"x":"94b0fc1525bcabf82b1f34895e5819a06c02b23e04002276e165f962c86e3927","y":"be7c2ab4d0b25303204fb32a1f8292902792225e16a6d2dbfb29fbc89a9c3376","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"8ef071c02383d2a6c02dc217bbffd446730d0318b0425e2586220907f885f97f","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #672: edge case for u1"} +{"x":"5351f37e1de0c88c508527d89882d183ccdcf2efca407edb0627cadfd16de6ec","y":"44b4b57cdf960d32ebcc4c97847eed218425853b5b675eb781b766a1a1300349","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"5668aaa0b545bbf9a044a32399ffbe69ce20074e34d7bdf5cf56282a76976396","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #673: edge case for u1"} +{"x":"748bbafc320e6735cb64019710a269c6c2b5d147bdc831325cb2fb276ac971a6","y":"9d655e9a755bc9d800ad21ee3fd4d980d93a7a49a8c5ccd37005177578f51163","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"d12d6e56882f6c0027cae91a27127728f7fddf478fb4fdc2b65f40a60b0eb952","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #674: edge case for u1"} +{"x":"14b3bbd75c5e1c0c36535a934d4ab85112410b3b90fa97a31c33038964fd85cc","y":"112f7d837f8f9c36b460d636c965a5f818f2b50c5d00fb3f9705561dd6631883","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"7fffffffaaaaaaaaffffffffffffffffe9a2538f37b28a2c513dee40fecbb71a","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #675: edge case for u2"} +{"x":"d823533c04cd8edc6d6f950a8e08ade04a9bafa2f14a590356935671ae9305bf","y":"43178d1f88b6a57a96924c265f0ddb75b58312907b195acb59d7797303123775","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"b62f26b5f2a2b26f6de86d42ad8a13da3ab3cccd0459b201de009e526adf21f2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #676: edge case for u2"} +{"x":"db2b3408b3167d91030624c6328e8ce3ec108c105575c2f3d209b92e654bab69","y":"c34318139c50b0802c6e612f0fd3189d800df7c996d5d7b7c3d6be82836fa258","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bb1d9ac949dd748cd02bbbe749bd351cd57b38bb61403d700686aa7b4c90851e","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #677: edge case for u2"} +{"x":"09179ce7c59225392216453b2ac1e9d178c24837dfae26bc1dd7ab6063852742","y":"5556b42e330289f3b826b2db7a86d19d45c2860a59f2be1ddcc3b691f95a9255","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"66755a00638cdaec1c732513ca0234ece52545dac11f816e818f725b4f60aaf2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #678: edge case for u2"} +{"x":"01959fb8deda56e5467b7e4b214ea4c2d0c2fb29d70ff19b6b1eccebd6568d7e","y":"d9dbd77a918297fd970bff01e1343f6925167db5a14d098a211c39cc3a413398","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"55a00c9fcdaebb6032513ca0234ecfffe98ebe492fdf02e48ca48e982beb3669","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #679: edge case for u2"} +{"x":"567f1fdc387e5350c852b4e8f8ba9d6d947e1c5dd7ccc61a5938245dd6bcab3a","y":"9960bebaf919514f9535c22eaaf0b5812857970e26662267b1f3eb1011130a11","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"ab40193f9b5d76c064a27940469d9fffd31d7c925fbe05c919491d3057d66cd2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #680: edge case for u2"} +{"x":"3499f974ff4ca6bbb2f51682fd5f51762f9dd6dd2855262660b36d46d3e4bec2","y":"f498fae2487807e220119152f0122476c64d4fa46ddce85c4546630f0d5c5e81","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"ca0234ebb5fdcb13ca0234ecffffffffcb0dadbbc7f549f8a26b4408d0dc8600","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #681: edge case for u2"} +{"x":"2c5c01662cf00c1929596257db13b26ecf30d0f3ec4b9f0351b0f27094473426","y":"e986a086060d086eee822ddd2fc744247a0154b57f7a69c51d9fdafa484e4ac7","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff3ea3677e082b9310572620ae19933a9e65b285598711c77298815ad3","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #682: edge case for u2"} +{"x":"91d4cba813a04d86dbae94c23be6f52c15774183be7ba5b2d9f3cf010b160501","y":"900b8adfea6491019a9ac080d516025a541bf4b952b0ad7be4b1874b02fd544a","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"266666663bbbbbbbe6666666666666665b37902e023fab7c8f055d86e5cc41f4","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #683: edge case for u2"} +{"x":"ef7fd0a3a36386638330ecad41e1a3b302af36960831d0210c614b948e8aa124","y":"ef0d6d800e4047d6d3c1be0fdeaf11fcd8cab5ab59c730eb34116e35a8c7d098","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff36db6db7a492492492492492146c573f4c6dfc8d08a443e258970b09","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #684: edge case for u2"} +{"x":"a521dab13cc9152d8ca77035a607fea06c55cc3ca5dbeb868cea92eafe93df2a","y":"7bfb9b28531996635e6a5ccaa2826a406ce1111bdb9c2e0ca36500418a2f43de","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff2aaaaaab7fffffffffffffffc815d0e60b3e596ecb1ad3a27cfd49c4","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #685: edge case for u2"} +{"x":"474d58a4eec16e0d565f2187fe11d4e8e7a2683a12f38b4fc01d1237a81a1097","y":"6e55f73bb7cdda46bdb67ef77f6fd2969df2b67920fb5945fde3a517a6ded4cd","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"7fffffff55555555ffffffffffffffffd344a71e6f651458a27bdc81fd976e37","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #686: edge case for u2"} +{"x":"692da5cd4309d9a6e5cb525c37da8fa0879f7b57208cdabbf47d223a5b23a621","y":"40e0daa78cfdd207a7389aaed61738b17fc5fc3e6a5ed3397d2902e9125e6ab4","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"3fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192aa","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #687: edge case for u2"} +{"x":"85689b3e0775c7718a90279f14a8082cfcd4d1f1679274f4e9b8805c570a0670","y":"167fcc5ca734552e09afa3640f4a034e15b9b7ca661ec7ff70d3f240ebe705b1","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"5d8ecd64a4eeba466815ddf3a4de9a8e6abd9c5db0a01eb80343553da648428f","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #688: edge case for u2"} +{"x":"0158137755b901f797a90d4ca8887e023cb2ef63b2ba2c0d455edaef42cf237e","y":"2a964fc00d377a8592b8b61aafa7a4aaa7c7b9fd2b41d6e0e17bd1ba5677edcd","r":"6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569","s":"f21d907e3890916dc4fa1f4703c1e50d3f54ddf7383e44023a41de562aa18ed8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #689: point duplication during verification"} +{"x":"0158137755b901f797a90d4ca8887e023cb2ef63b2ba2c0d455edaef42cf237e","y":"d569b03ef2c8857b6d4749e550585b5558384603d4be291f1e842e45a9881232","r":"6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569","s":"f21d907e3890916dc4fa1f4703c1e50d3f54ddf7383e44023a41de562aa18ed8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #690: duplication bug"} +{"x":"664ce273320d918d8bdb2e61201b4549b36b7cdc54e33b84adb6f2c10aac831e","y":"49e68831f18bda2973ac3d76bfbc8c5ee1cceed2dd862e2dc7c915c736cef1f4","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aa9","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #693: comparison with point at infinity "} +{"x":"961691a5e960d07a301dbbad4d86247ec27d7089faeb3ddd1add395efff1e0fe","y":"7254622cc371866cdf990d2c5377790e37d1f1519817f09a231bd260a9e78aeb","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #694: extreme value for k and edgecase s"} +{"x":"5d283e13ce8ca60da868e3b0fb33e6b4f1074793274e2928250e71e2aca63e9c","y":"214dc74fa25371fb4d9e506d418ed9a1bfd6d0c8bb6591d3e0f44505a84886ce","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #695: extreme value for k and s^-1"} +{"x":"0fc351da038ae0803bd1d86514ae0462f9f8216551d9315aa9d297f792eef6a3","y":"41c74eed786f2d33da35360ca7aa925e753f00d6077a1e9e5fc339d634019c73","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #696: extreme value for k and s^-1"} +{"x":"a1e34c8f16d138673fee55c080547c2bfd4de7550065f638322bba9430ce4b60","y":"662be9bb512663aa4d7df8ab3f3b4181c5d44a7bdf42436620b7d8a6b81ac936","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #697: extreme value for k and s^-1"} +{"x":"7e1a8a8338d7fd8cf41d322a302d2078a87a23c7186150ed7cda6e52817c1bdf","y":"d0a9135a89d21ce821e29014b2898349254d748272b2d4eb8d59ee34c615377f","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"49249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #698: extreme value for k and s^-1"} +{"x":"5c19fe227a61abc65c61ee7a018cc9571b2c6f663ea33583f76a686f64be078b","y":"7b4a0d734940f613d52bc48673b457c2cf78492490a5cc5606c0541d17b24ddb","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"16a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #699: extreme value for k"} +{"x":"db02d1f3421d600e9d9ef9e47419dba3208eed08c2d4189a5db63abeb2739666","y":"e0ed26967b9ada9ed7ffe480827f90a0d210d5fd8ec628e31715e6b24125512a","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #700: extreme value for k and edgecase s"} +{"x":"6222d1962655501893c29e441395b6c05711bd3ed5a0ef72cfab338b88229c4b","y":"aaae079cb44a1af070362aaa520ee24cac2626423b0bf81af1c54311d8e2fd23","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #701: extreme value for k and s^-1"} +{"x":"4ccfa24c67f3def7fa81bc99c70bb0419c0952ba599f4c03361da184b04cdca5","y":"db76b797f7f41d9c729a2219478a7e629728df870800be8cf6ca7a0a82153bfa","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #702: extreme value for k and s^-1"} +{"x":"ea1c72c91034036bac71402b6e9ecc4af3dbde7a99dc574061e99fefff9d84da","y":"b7dd057e75b78ac6f56e34eb048f0a9d29d5d055408c90d02bc2ea918c18cb63","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #703: extreme value for k and s^-1"} +{"x":"c2879a66d86cb20b820b7795da2da62b38924f7817d1cd350d936988e90e79bc","y":"5431a7268ff6931c7a759de024eff90bcb0177216db6fd1f3aaaa11fa3b6a083","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"49249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #704: extreme value for k and s^-1"} +{"x":"ab1c0f273f74abc2b848c75006f2ef3c54c26df27711b06558f455079aee0ba3","y":"df510f2ecef6d9a05997c776f14ad6456c179f0a13af1771e4d6c37fa48b47f2","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"16a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #705: extreme value for k"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5","r":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #706: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5","r":"acd155416a8b77f34089464733ff7cd39c400e9c69af7beb9eac5054ed2ec72c","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #707: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a","r":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #708: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a","r":"acd155416a8b77f34089464733ff7cd39c400e9c69af7beb9eac5054ed2ec72c","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #709: testing point duplication"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"a8ea150cb80125d7381c4c1f1da8e9de2711f9917060406a73d7904519e51388","s":"f3ab9fa68bd47973a73b2d40480c2ba50c22c9d76ec217257288293285449b86","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1210: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"30e782f964b2e2ff065a051bc7adc20615d8c43a1365713c88268822c253bcce","s":"5b16df652aa1ecb2dc8b46c515f9604e2e84cacfa7c6eec30428d2d3f4e08ed5","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1211: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"b292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a","s":"0177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2","hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","valid":true,"msg":"","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1212: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"986e65933ef2ed4ee5aada139f52b70539aaf63f00a91f29c69178490d57fb71","s":"3dafedfb8da6189d372308cbf1489bbbdabf0c0217d1c0ff0f701aaa7a694b9c","hash":"de47c9b27eb8d300dbb5f2c353e632c393262cf06340c4fa7f1b40c4cbd36f90","valid":true,"msg":"0000000000000000000000000000000000000000","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1213: pseudorandom signature"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"d434e262a49eab7781e353a3565e482550dd0fd5defa013c7f29745eff3569f1","s":"9b0c0a93f267fb6052fd8077be769c2b98953195d7bc10de844218305c6ba17a","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1303: x-coordinate of the public key has many trailing 0's"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"0fe774355c04d060f76d79fd7a772e421463489221bf0a33add0be9b1979110b","s":"500dcba1c69a8fbd43fa4f57f743ce124ca8b91a1f325f3fac6181175df55737","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1304: x-coordinate of the public key has many trailing 0's"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"bb40bf217bed3fb3950c7d39f03d36dc8e3b2cd79693f125bfd06595ee1135e3","s":"541bf3532351ebb032710bdb6a1bf1bfc89a1e291ac692b3fa4780745bb55677","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1305: x-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"664eb7ee6db84a34df3c86ea31389a5405badd5ca99231ff556d3e75a233e73a","s":"59f3c752e52eca46137642490a51560ce0badc678754b8f72e51a2901426a1bd","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1306: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"4cd0429bbabd2827009d6fcd843d4ce39c3e42e2d1631fd001985a79d1fd8b43","s":"9638bf12dd682f60be7ef1d0e0d98f08b7bca77a1a2b869ae466189d2acdabe3","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1307: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"e56c6ea2d1b017091c44d8b6cb62b9f460e3ce9aed5e5fd41e8added97c56c04","s":"a308ec31f281e955be20b457e463440b4fcf2b80258078207fc1378180f89b55","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1308: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"1158a08d291500b4cabed3346d891eee57c176356a2624fb011f8fbbf3466830","s":"228a8c486a736006e082325b85290c5bc91f378b75d487dda46798c18f285519","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1309: y-coordinate of the public key has many trailing 1's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"b1db9289649f59410ea36b0c0fc8d6aa2687b29176939dd23e0dde56d309fa9d","s":"3e1535e4280559015b0dbd987366dcf43a6d1af5c23c7d584e1c3f48a1251336","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1310: y-coordinate of the public key has many trailing 1's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"b7b16e762286cb96446aa8d4e6e7578b0a341a79f2dd1a220ac6f0ca4e24ed86","s":"ddc60a700a139b04661c547d07bbb0721780146df799ccf55e55234ecb8f12bc","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1311: y-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"d82a7c2717261187c8e00d8df963ff35d796edad36bc6e6bd1c91c670d9105b4","s":"3dcabddaf8fcaa61f4603e7cbac0f3c0351ecd5988efb23f680d07debd139929","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1312: x-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"5eb9c8845de68eb13d5befe719f462d77787802baff30ce96a5cba063254af78","s":"2c026ae9be2e2a5e7ca0ff9bbd92fb6e44972186228ee9a62b87ddbe2ef66fb5","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1313: x-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"96843dd03c22abd2f3b782b170239f90f277921becc117d0404a8e4e36230c28","s":"f2be378f526f74a543f67165976de9ed9a31214eb4d7e6db19e1ede123dd991d","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1314: x-coordinate of the public key has many trailing 1's"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"766456dce1857c906f9996af729339464d27e9d98edc2d0e3b760297067421f6","s":"402385ecadae0d8081dccaf5d19037ec4e55376eced699e93646bfbbf19d0b41","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1315: x-coordinate of the public key is large"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"c605c4b2edeab20419e6518a11b2dbc2b97ed8b07cced0b19c34f777de7b9fd9","s":"edf0f612c5f46e03c719647bc8af1b29b2cde2eda700fb1cff5e159d47326dba","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1316: x-coordinate of the public key is large"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"d48b68e6cabfe03cf6141c9ac54141f210e64485d9929ad7b732bfe3b7eb8a84","s":"feedae50c61bd00e19dc26f9b7e2265e4508c389109ad2f208f0772315b6c941","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1317: x-coordinate of the public key is large"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"b7c81457d4aeb6aa65957098569f0479710ad7f6595d5874c35a93d12a5dd4c7","s":"b7961a0b652878c2d568069a432ca18a1a9199f2ca574dad4b9e3a05c0a1cdb3","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1318: x-coordinate of the public key is small"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"6b01332ddb6edfa9a30a1321d5858e1ee3cf97e263e669f8de5e9652e76ff3f7","s":"5939545fced457309a6a04ace2bd0f70139c8f7d86b02cb1cc58f9e69e96cd5a","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1319: x-coordinate of the public key is small"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"efdb884720eaeadc349f9fc356b6c0344101cd2fd8436b7d0e6a4fb93f106361","s":"f24bee6ad5dc05f7613975473aadf3aacba9e77de7d69b6ce48cb60d8113385d","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1320: x-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"31230428405560dcb88fb5a646836aea9b23a23dd973dcbe8014c87b8b20eb07","s":"0f9344d6e812ce166646747694a41b0aaf97374e19f3c5fb8bd7ae3d9bd0beff","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1321: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"caa797da65b320ab0d5c470cda0b36b294359c7db9841d679174db34c4855743","s":"cf543a62f23e212745391aaf7505f345123d2685ee3b941d3de6d9b36242e5a0","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1322: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"7e5f0ab5d900d3d3d7867657e5d6d36519bc54084536e7d21c336ed800185945","s":"9450c07f201faec94b82dfb322e5ac676688294aad35aa72e727ff0b19b646aa","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1323: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"d7d70c581ae9e3f66dc6a480bf037ae23f8a1e4a2136fe4b03aa69f0ca25b356","s":"89c460f8a5a5c2bbba962c8a3ee833a413e85658e62a59e2af41d9127cc47224","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1324: y-coordinate of the public key is large"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"341c1b9ff3c83dd5e0dfa0bf68bcdf4bb7aa20c625975e5eeee34bb396266b34","s":"72b69f061b750fd5121b22b11366fad549c634e77765a017902a67099e0a4469","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1325: y-coordinate of the public key is large"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"70bebe684cdcb5ca72a42f0d873879359bd1781a591809947628d313a3814f67","s":"aec03aca8f5587a4d535fa31027bbe9cc0e464b1c3577f4c2dcde6b2094798a9","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1326: y-coordinate of the public key is large"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"4cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #1: signature malleability"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5740946b2a147f59262ee6f5bc90bd01ed280528b62b3aed5fc93f06f739","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #3: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"d45c5741946b2a137f59262ee6f5bc91001af27a5e1117a64733950642a3d1e8","s":"b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #5: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18","s":"4cd60b865d442f5a3c7b11eb6c4e0ae79578ec6353a20bf783ecb4b6ea97b825","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #8: Modified r or s, e.g. by adding or subtracting the order of the group"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #9: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #10: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #11: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #12: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #13: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #14: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000000","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #15: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #16: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #17: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #18: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #19: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #20: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #21: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #22: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #23: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #24: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #25: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #26: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #27: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #28: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #29: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #30: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #31: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #32: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #33: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #34: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #35: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #36: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #37: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #38: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #39: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #40: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #41: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #42: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #43: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #44: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #45: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #46: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #47: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #48: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #49: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #50: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #51: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #52: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #53: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #54: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #55: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000001000000000000000000000000ffffffffffffffffffffffff","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #56: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffffffff00000001000000000000000000000001000000000000000000000000","s":"ffffffff00000001000000000000000000000001000000000000000000000000","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":false,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #57: Signature with special case values for r and s"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"64a1aab5000d0e804f3e2fc02bdee9be8ff312334e2ba16d11547c97711c898e","s":"6af015971cc30be6d1a206d4e013e0997772a2f91d73286ffd683b9bb2cf4f1b","hash":"70239dd877f7c944c422f44dea4ed1a52f2627416faf2f072fa50c772ed6f807","valid":true,"msg":"3639383139","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #58: Edge case for Shamir multiplication"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"16aea964a2f6506d6f78c81c91fc7e8bded7d397738448de1e19a0ec580bf266","s":"252cd762130c6667cfe8b7bc47d27d78391e8e80c578d1cd38c3ff033be928e9","hash":"00000000690ed426ccf17803ebe2bd0884bcd58a1bb5e7477ead3645f356e7a9","valid":true,"msg":"343236343739373234","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #59: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9cc98be2347d469bf476dfc26b9b733df2d26d6ef524af917c665baccb23c882","s":"093496459effe2d8d70727b82462f61d0ec1b7847929d10ea631dacb16b56c32","hash":"7300000000213f2a525c6035725235c2f696ad3ebb5ee47f140697ad25770d91","valid":true,"msg":"37313338363834383931","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #60: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"73b3c90ecd390028058164524dde892703dce3dea0d53fa8093999f07ab8aa43","s":"2f67b0b8e20636695bb7d8bf0a651c802ed25a395387b5f4188c0c4075c88634","hash":"ddf2000000005e0be0635b245f0b97978afd25daadeb3edb4a0161c27fe06045","valid":true,"msg":"3130333539333331363638","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #61: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bfab3098252847b328fadf2f89b95c851a7f0eb390763378f37e90119d5ba3dd","s":"bdd64e234e832b1067c2d058ccb44d978195ccebb65c2aaf1e2da9b8b4987e3b","hash":"67ab1900000000784769c4ecb9e164d6642b8499588b89855be1ec355d0841a0","valid":true,"msg":"33393439343031323135","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #62: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"204a9784074b246d8bf8bf04a4ceb1c1f1c9aaab168b1596d17093c5cd21d2cd","s":"51cce41670636783dc06a759c8847868a406c2506fe17975582fe648d1d88b52","hash":"a2bf09460000000076d7dbeffe125eaf02095dff252ee905e296b6350fc311cf","valid":true,"msg":"31333434323933303739","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #63: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ed66dc34f551ac82f63d4aa4f81fe2cb0031a91d1314f835027bca0f1ceeaa03","s":"99ca123aa09b13cd194a422e18d5fda167623c3f6e5d4d6abb8953d67c0c48c7","hash":"3554e827c700000000e1e75e624a06b3a0a353171160858129e15c544e4f0e65","valid":true,"msg":"33373036323131373132","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #64: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"060b700bef665c68899d44f2356a578d126b062023ccc3c056bf0f60a237012b","s":"8d186c027832965f4fcc78a3366ca95dedbb410cbef3f26d6be5d581c11d3610","hash":"9b6cd3b812610000000026941a0f0bb53255ea4c9fd0cb3426e3a54b9fc6965c","valid":true,"msg":"333433363838373132","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #65: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9f6adfe8d5eb5b2c24d7aa7934b6cf29c93ea76cd313c9132bb0c8e38c96831d","s":"b26a9c9e40e55ee0890c944cf271756c906a33e66b5bd15e051593883b5e9902","hash":"883ae39f50bf0100000000e7561c26fc82a52baa51c71ca877162f93c4ae0186","valid":true,"msg":"31333531353330333730","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #66: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a1af03ca91677b673ad2f33615e56174a1abf6da168cebfa8868f4ba273f16b7","s":"20aa73ffe48afa6435cd258b173d0c2377d69022e7d098d75caf24c8c5e06b1c","hash":"a1ce5d6e5ecaf28b0000000000fa7cd010540f420fb4ff7401fe9fce011d0ba6","valid":true,"msg":"36353533323033313236","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #67: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"fdc70602766f8eed11a6c99a71c973d5659355507b843da6e327a28c11893db9","s":"3df5349688a085b137b1eacf456a9e9e0f6d15ec0078ca60a7f83f2b10d21350","hash":"8ea5f645f373f580930000000038345397330012a8ee836c5494cdffd5ee8054","valid":true,"msg":"31353634333436363033","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #68: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"b516a314f2fce530d6537f6a6c49966c23456f63c643cf8e0dc738f7b876e675","s":"d39ffd033c92b6d717dd536fbc5efdf1967c4bd80954479ba66b0120cd16fff2","hash":"660570d323e9f75fa734000000008792d65ce93eabb7d60d8d9c1bbdcb5ef305","valid":true,"msg":"34343239353339313137","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #69: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"3b2cbf046eac45842ecb7984d475831582717bebb6492fd0a485c101e29ff0a8","s":"4c9b7b47a98b0f82de512bc9313aaf51701099cac5f76e68c8595fc1c1d99258","hash":"d0462673154cce587dde8800000000e98d35f1f45cf9c3bf46ada2de4c568c34","valid":true,"msg":"3130393533323631333531","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #70: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"30c87d35e636f540841f14af54e2f9edd79d0312cfa1ab656c3fb15bfde48dcf","s":"47c15a5a82d24b75c85a692bd6ecafeb71409ede23efd08e0db9abf6340677ed","hash":"bd90640269a7822680cedfef000000000caef15a6171059ab83e7b4418d7278f","valid":true,"msg":"35393837333530303431","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #71: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"38686ff0fda2cef6bc43b58cfe6647b9e2e8176d168dec3c68ff262113760f52","s":"067ec3b651f422669601662167fa8717e976e2db5e6a4cf7c2ddabb3fde9d67d","hash":"33239a52d72f1311512e41222a00000000d2dcceb301c54b4beae8e284788a73","valid":true,"msg":"33343633303036383738","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #72: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"44a3e23bf314f2b344fc25c7f2de8b6af3e17d27f5ee844b225985ab6e2775cf","s":"2d48e223205e98041ddc87be532abed584f0411f5729500493c9cc3f4dd15e86","hash":"b8d64fbcd4a1c10f1365d4e6d95c000000007ee4a21a1cbe1dc84c2d941ffaf1","valid":true,"msg":"39383137333230323837","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #73: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ded5b7ec8e90e7bf11f967a3d95110c41b99db3b5aa8d330eb9d638781688e9","s":"7d5792c53628155e1bfc46fb1a67e3088de049c328ae1f44ec69238a009808f9","hash":"01603d3982bf77d7a3fef3183ed092000000003a227420db4088b20fe0e9d84a","valid":true,"msg":"33323232303431303436","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #74: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bdae7bcb580bf335efd3bc3d31870f923eaccafcd40ec2f605976f15137d8b8f","s":"f6dfa12f19e525270b0106eecfe257499f373a4fb318994f24838122ce7ec3c7","hash":"9ea6994f1e0384c8599aa02e6cf66d9c000000004d89ef50b7e9eb0cfbff7363","valid":true,"msg":"36363636333037313034","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #75: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"50f9c4f0cd6940e162720957ffff513799209b78596956d21ece251c2401f1c6","s":"d7033a0a787d338e889defaaabb106b95a4355e411a59c32aa5167dfab244726","hash":"d03215a8401bcf16693979371a01068a4700000000e2fa5bf692bc670905b18c","valid":true,"msg":"31303335393531383938","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #76: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"f612820687604fa01906066a378d67540982e29575d019aabe90924ead5c860d","s":"3f9367702dd7dd4f75ea98afd20e328a1a99f4857b316525328230ce294b0fef","hash":"307bfaaffb650c889c84bf83f0300e5dc87e000000008408fd5f64b582e3bb14","valid":true,"msg":"31383436353937313935","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #77: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"9505e407657d6e8bc93db5da7aa6f5081f61980c1949f56b0f2f507da5782a7a","s":"c60d31904e3669738ffbeccab6c3656c08e0ed5cb92b3cfa5e7f71784f9c5021","hash":"bab5c4f4df540d7b33324d36bb0c157551527c00000000e4af574bb4d54ea6b8","valid":true,"msg":"33313336303436313839","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #78: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bbd16fbbb656b6d0d83e6a7787cd691b08735aed371732723e1c68a40404517d","s":"9d8e35dba96028b7787d91315be675877d2d097be5e8ee34560e3e7fd25c0f00","hash":"d4ba47f6ae28f274e4f58d8036f9c36ec2456f5b00000000c3b869197ef5e15e","valid":true,"msg":"32363633373834323534","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #79: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2ec9760122db98fd06ea76848d35a6da442d2ceef7559a30cf57c61e92df327e","s":"7ab271da90859479701fccf86e462ee3393fb6814c27b760c4963625c0a19878","hash":"79fd19c7235ea212f29f1fa00984342afe0f10aafd00000000801e47f8c184e1","valid":true,"msg":"31363532313030353234","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #80: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"54e76b7683b6650baa6a7fc49b1c51eed9ba9dd463221f7a4f1005a89fe00c59","s":"2ea076886c773eb937ec1cc8374b7915cfd11b1c1ae1166152f2f7806a31c8fd","hash":"8c291e8eeaa45adbaf9aba5c0583462d79cbeb7ac97300000000a37ea6700cda","valid":true,"msg":"35373438303831363936","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #81: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5291deaf24659ffbbce6e3c26f6021097a74abdbb69be4fb10419c0c496c9466","s":"65d6fcf336d27cc7cdb982bb4e4ecef5827f84742f29f10abf83469270a03dc3","hash":"0eaae8641084fa979803efbfb8140732f4cdcf66c3f78a000000003c278a6b21","valid":true,"msg":"36333433393133343638","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #82: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"207a3241812d75d947419dc58efb05e8003b33fc17eb50f9d15166a88479f107","s":"cdee749f2e492b213ce80b32d0574f62f1c5d70793cf55e382d5caadf7592767","hash":"e02716d01fb23a5a0068399bf01bab42ef17c6d96e13846c00000000afc0f89d","valid":true,"msg":"31353431313033353938","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #83: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"6554e49f82a855204328ac94913bf01bbe84437a355a0a37c0dee3cf81aa7728","s":"aea00de2507ddaf5c94e1e126980d3df16250a2eaebc8be486effe7f22b4f929","hash":"9eb0bf583a1a6b9a194e9a16bc7dab2a9061768af89d00659a00000000fc7de1","valid":true,"msg":"3130343738353830313238","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #84: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a54c5062648339d2bff06f71c88216c26c6e19b4d80a8c602990ac82707efdfc","s":"e99bbe7fcfafae3e69fd016777517aa01056317f467ad09aff09be73c9731b0d","hash":"62aac98818b3b84a2c214f0d5e72ef286e1030cb53d9a82b690e00000000cd15","valid":true,"msg":"3130353336323835353638","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #85: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"975bd7157a8d363b309f1f444012b1a1d23096593133e71b4ca8b059cff37eaf","s":"7faa7a28b1c822baa241793f2abc930bd4c69840fe090f2aacc46786bf919622","hash":"3760a7f37cf96218f29ae43732e513efd2b6f552ea4b6895464b9300000000c8","valid":true,"msg":"393533393034313035","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #86: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5694a6f84b8f875c276afd2ebcfe4d61de9ec90305afb1357b95b3e0da43885e","s":"0dffad9ffd0b757d8051dec02ebdf70d8ee2dc5c7870c0823b6ccc7c679cbaa4","hash":"0da0a1d2851d33023834f2098c0880096b4320bea836cd9cbb6ff6c800000000","valid":true,"msg":"393738383438303339","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #87: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"a0c30e8026fdb2b4b4968a27d16a6d08f7098f1a98d21620d7454ba9790f1ba6","s":"5e470453a8a399f15baf463f9deceb53acc5ca64459149688bd2760c65424339","hash":"ffffffff293886d3086fd567aafd598f0fe975f735887194a764a231e82d289a","valid":true,"msg":"33363130363732343432","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #88: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"614ea84acf736527dd73602cd4bb4eea1dfebebd5ad8aca52aa0228cf7b99a88","s":"737cc85f5f2d2f60d1b8183f3ed490e4de14368e96a9482c2a4dd193195c902f","hash":"7bffffffff2376d1e3c03445a072e24326acdc4ce127ec2e0e8d9ca99527e7b7","valid":true,"msg":"31303534323430373035","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #89: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"bead6734ebe44b810d3fb2ea00b1732945377338febfd439a8d74dfbd0f942fa","s":"6bb18eae36616a7d3cad35919fd21a8af4bbe7a10f73b3e036a46b103ef56e2a","hash":"a2b5ffffffffebb251b085377605a224bc80872602a6e467fd016807e97fa395","valid":true,"msg":"35313734343438313937","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #90: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"499625479e161dacd4db9d9ce64854c98d922cbf212703e9654fae182df9bad2","s":"42c177cf37b8193a0131108d97819edd9439936028864ac195b64fca76d9d693","hash":"641227ffffffff6f1b96fa5f097fcf3cc1a3c256870d45a67b83d0967d4b20c0","valid":true,"msg":"31393637353631323531","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #91: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"08f16b8093a8fb4d66a2c8065b541b3d31e3bfe694f6b89c50fb1aaa6ff6c9b2","s":"9d6455e2d5d1779748573b611cb95d4a21f967410399b39b535ba3e5af81ca2e","hash":"958415d8ffffffffabad03e2fc662dc3ba203521177502298df56f36600e0f8b","valid":true,"msg":"33343437323533333433","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #92: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"be26231b6191658a19dd72ddb99ed8f8c579b6938d19bce8eed8dc2b338cb5f8","s":"e1d9a32ee56cffed37f0f22b2dcb57d5c943c14f79694a03b9c5e96952575c89","hash":"f1d8de4858ffffffff1281093536f47fe13deb04e1fbe8fb954521b6975420f8","valid":true,"msg":"333638323634333138","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #93: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"15e76880898316b16204ac920a02d58045f36a229d4aa4f812638c455abe0443","s":"e74d357d3fcb5c8c5337bd6aba4178b455ca10e226e13f9638196506a1939123","hash":"0927895f2802ffffffff10782dd14a3b32dc5d47c05ef6f1876b95c81fc31def","valid":true,"msg":"33323631313938363038","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #94: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"352ecb53f8df2c503a45f9846fc28d1d31e6307d3ddbffc1132315cc07f16dad","s":"1348dfa9c482c558e1d05c5242ca1c39436726ecd28258b1899792887dd0a3c6","hash":"60907984aa7e8effffffff4f332862a10a57c3063fb5a30624cf6a0c3ac80589","valid":true,"msg":"39363738373831303934","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #95: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"4a40801a7e606ba78a0da9882ab23c7677b8642349ed3d652c5bfa5f2a9558fb","s":"3a49b64848d682ef7f605f2832f7384bdc24ed2925825bf8ea77dc5981725782","hash":"c6ff198484939170ffffffff0af42cda50f9a5f50636ea6942d6b9b8cd6ae1e2","valid":true,"msg":"34393538383233383233","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #96: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"eacc5e1a8304a74d2be412b078924b3bb3511bac855c05c9e5e9e44df3d61e96","s":"7451cd8e18d6ed1885dd827714847f96ec4bb0ed4c36ce9808db8f714204f6d1","hash":"de030419345ca15c75ffffffff8074799b9e0956cc43135d16dfbe4d27d7e68d","valid":true,"msg":"383234363337383337","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #97: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"2f7a5e9e5771d424f30f67fdab61e8ce4f8cd1214882adb65f7de94c31577052","s":"ac4e69808345809b44acb0b2bd889175fb75dd050c5a449ab9528f8f78daa10c","hash":"6f0e3eeaf42b28132b88fffffffff6c8665604d34acb19037e1ab78caaaac6ff","valid":true,"msg":"3131303230383333373736","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #98: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ffcda40f792ce4d93e7e0f0e95e1a2147dddd7f6487621c30a03d710b3300219","s":"79938b55f8a17f7ed7ba9ade8f2065a1fa77618f0b67add8d58c422c2453a49a","hash":"cdb549f773b3e62b3708d1ffffffffbe48f7c0591ddcae7d2cb222d1f8017ab9","valid":true,"msg":"313333383731363438","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #99: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"81f2359c4faba6b53d3e8c8c3fcc16a948350f7ab3a588b28c17603a431e39a8","s":"cd6f6a5cc3b55ead0ff695d06c6860b509e46d99fccefb9f7f9e101857f74300","hash":"2c3f26f96a3ac0051df4989bffffffff9fd64886c1dc4f9924d8fd6f0edb0484","valid":true,"msg":"333232313434313632","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #100: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"dfc8bf520445cbb8ee1596fb073ea283ea130251a6fdffa5c3f5f2aaf75ca808","s":"048e33efce147c9dd92823640e338e68bfd7d0dc7a4905b3a7ac711e577e90e7","hash":"ac18f8418c55a2502cb7d53f9affffffff5c31d89fda6a6b8476397c04edf411","valid":true,"msg":"3130363836363535353436","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #101: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ad019f74c6941d20efda70b46c53db166503a0e393e932f688227688ba6a5762","s":"93320eb7ca0710255346bdbb3102cdcf7964ef2e0988e712bc05efe16c199345","hash":"4f9618f98e2d3a15b24094f72bb5ffffffffa2fd3e2893683e5a6ab8cf0ee610","valid":true,"msg":"3632313535323436","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #102: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"ac8096842e8add68c34e78ce11dd71e4b54316bd3ebf7fffdeb7bd5a3ebc1883","s":"f5ca2f4f23d674502d4caf85d187215d36e3ce9f0ce219709f21a3aac003b7a8","hash":"422e82a3d56ed10a9cc21d31d37a25ffffffff67edf7c40204caae73ab0bc75a","valid":true,"msg":"37303330383138373734","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #103: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"677b2d3a59b18a5ff939b70ea002250889ddcd7b7b9d776854b4943693fb92f7","s":"6b4ba856ade7677bf30307b21f3ccda35d2f63aee81efd0bab6972cc0795db55","hash":"7075d245ccc3281b6e7b329ff738fbb417a5ffffffffa0842d9890b5cf95d018","valid":true,"msg":"35393234353233373434","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #104: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"479e1ded14bcaed0379ba8e1b73d3115d84d31d4b7c30e1f05e1fc0d5957cfb0","s":"918f79e35b3d89487cf634a4f05b2e0c30857ca879f97c771e877027355b2443","hash":"3c80de54cd9226989443d593fa4fd6597e280ebeffffffffc1847eb76c217a95","valid":true,"msg":"31343935353836363231","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #105: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"43dfccd0edb9e280d9a58f01164d55c3d711e14b12ac5cf3b64840ead512a0a3","s":"1dbe33fa8ba84533cd5c4934365b3442ca1174899b78ef9a3199f49584389772","hash":"de21754e29b85601980bef3d697ea2770ce891a8cdffffffffc7906aa794b39b","valid":true,"msg":"34303035333134343036","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #106: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5b09ab637bd4caf0f4c7c7e4bca592fea20e9087c259d26a38bb4085f0bbff11","s":"45b7eb467b6748af618e9d80d6fdcd6aa24964e5a13f885bca8101de08eb0d75","hash":"8f65d92927cfb86a84dd59623fb531bb599e4d5f7289ffffffff2f1f2f57881c","valid":true,"msg":"33303936343537353132","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #107: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"5e9b1c5a028070df5728c5c8af9b74e0667afa570a6cfa0114a5039ed15ee06f","s":"b1360907e2d9785ead362bb8d7bd661b6c29eeffd3c5037744edaeb9ad990c20","hash":"6b63e9a74e092120160bea3877dace8a2cc7cd0e8426cbfffffffffafc8c3ca8","valid":true,"msg":"32373834303235363230","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #108: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"0671a0a85c2b72d54a2fb0990e34538b4890050f5a5712f6d1a7a5fb8578f32e","s":"db1846bab6b7361479ab9c3285ca41291808f27fd5bd4fdac720e5854713694c","hash":"fc28259702a03845b6d75219444e8b43d094586e249c8699ffffffffe852512e","valid":true,"msg":"32363138373837343138","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #109: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"7673f8526748446477dbbb0590a45492c5d7d69859d301abbaedb35b2095103a","s":"3dc70ddf9c6b524d886bed9e6af02e0e4dec0d417a414fed3807ef4422913d7c","hash":"1273b4502ea4e3bccee044ee8e8db7f774ecbcd52e8ceb571757ffffffffe20a","valid":true,"msg":"31363432363235323632","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #110: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"7f085441070ecd2bb21285089ebb1aa6450d1a06c36d3ff39dfd657a796d12b5","s":"249712012029870a2459d18d47da9aa492a5e6cb4b2d8dafa9e4c5c54a2b9a8b","hash":"08fb565610a79baa0c566c66228d81814f8c53a15b96e602fb49ffffffffff6e","valid":true,"msg":"36383234313839343336","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #111: special case hash"} +{"x":"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838","y":"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e","r":"914c67fb61dd1e27c867398ea7322d5ab76df04bc5aa6683a8e0f30a5d287348","s":"fa07474031481dda4953e3ac1959ee8cea7e66ec412b38d6c96d28f6d37304ea","hash":"d59291cc2cf89f3087715fcb1aa4e79aa2403f748e97d7cd28ecaefeffffffff","valid":true,"msg":"343834323435343235","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #112: special case hash"} +{"x":"d705d16f80987e2d9b1a6957d29ce22febf7d10fa515153182415c8361baaca4","y":"b1fc105ee5ce80d514ec1238beae2037a6f83625593620d460819e8682160926","r":"000000000000000000000000000000004319055358e8617b0c46353d039cdaab","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #113: k*G has a large x-coordinate"} +{"x":"d705d16f80987e2d9b1a6957d29ce22febf7d10fa515153182415c8361baaca4","y":"b1fc105ee5ce80d514ec1238beae2037a6f83625593620d460819e8682160926","r":"ffffffff00000001000000000000000000000000fffffffffffffffffffffffc","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #114: r too large"} +{"x":"3cd8d2f81d6953b0844c09d7b560d527cd2ef67056893eadafa52c8501387d59","y":"ee41fdb4d10402ce7a0c5e3b747adfa3a490b62a6b7719068903485c0bb6dc2d","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #115: r,s are large"} +{"x":"8240cd81edd91cb6936133508c3915100e81f332c4545d41189b481196851378","y":"e05b06e72d4a1bff80ea5db514aa2f93ea6dd6d9c0ae27b7837dc432f9ce89d9","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"909135bdb6799286170f5ead2de4f6511453fe50914f3df2de54a36383df8dd4","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #116: r and s^-1 have a large Hamming weight"} +{"x":"b062947356748b0fc17f1704c65aa1dca6e1bfe6779756fa616d91eaad13df2c","y":"0b38c17f3d0672e7409cfc5992a99fff12b84a4f8432293b431113f1b2fb579d","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"27b4577ca009376f71303fd5dd227dcef5deb773ad5f5a84360644669ca249a5","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #117: r and s^-1 have a large Hamming weight"} +{"x":"4a03ef9f92eb268cafa601072489a56380fa0dc43171d7712813b3a19a1eb5e5","y":"3e213e28a608ce9a2f4a17fd830c6654018a79b3e0263d91a8ba90622df6f2f0","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #118: small r and s"} +{"x":"091194c1cba17f34e286b4833701606a41cef26177ada8850b601ea1f859e701","y":"27242fcec708828758403ce2fe501983a7984e6209f4d6b95db9ad77767f55eb","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"0000000000000000000000000000000000000000000000000000000000000003","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #120: small r and s"} +{"x":"103c6ecceff59e71ea8f56fee3a4b2b148e81c2bdbdd39c195812c96dcfb41a7","y":"2303a193dc591be150b883d770ec51ebb4ebce8b09042c2ecb16c448d8e57bf5","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"0000000000000000000000000000000000000000000000000000000000000005","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #122: small r and s"} +{"x":"3b66b829fe604638bcb2bfe8c22228be67390c20111bd2b451468927e87fb6ea","y":"bc8e59c009361758b274ba2cad36b58fde485a3ed09dade76712fa9e9c4ac212","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"0000000000000000000000000000000000000000000000000000000000000006","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #124: small r and s"} +{"x":"3b66b829fe604638bcb2bfe8c22228be67390c20111bd2b451468927e87fb6ea","y":"bc8e59c009361758b274ba2cad36b58fde485a3ed09dade76712fa9e9c4ac212","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632556","s":"0000000000000000000000000000000000000000000000000000000000000006","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #126: r is larger than n"} +{"x":"4ff2f6c24e4a33cd71c09fdcbc74a6233961b874b8c8e0eb94582092cbc50c30","y":"84fa9547afda5c66335f3f937d4c79afa120486b534139d59ae82d61ead26420","r":"0000000000000000000000000000000000000000000000000000000000000005","s":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc75fbd8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #127: s is larger than n"} +{"x":"84b959080bb30859cd53c2fb973cf14d60cdaa8ee00587889b5bc657ac588175","y":"a02ce5c1e53cb196113c78b4cb8dc7d360e5ea7850b0f6650b0c45af2c3cd7ca","r":"0000000000000000000000000000000000000000000000000000000000000100","s":"8f1e3c7862c58b16bb76eddbb76eddbb516af4f63f2d74d76e0d28c9bb75ea88","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #128: small r and s^-1"} +{"x":"df4083bd6ecbda5a77ae578e5d835fa7f74a07ebb91e0570e1ff32a563354e99","y":"25af80b09a167d9ef647df28e2d9acd0d4bc4f2deec5723818edaf9071e311f8","r":"000000000000000000000000000000000000000000000000002d9b4d347952d6","s":"ef3043e7329581dbb3974497710ab11505ee1c87ff907beebadd195a0ffe6d7a","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #129: smallish r and s^-1"} +{"x":"c2569a3c9bf8c1838ca821f7ba6f000cc8679d278f3736b414a34a7c956a0377","y":"0387ea85bc4f28804b4a91c9b7d65bc6434c975806795ab7d441a4e9683aeb09","r":"000000000000000000000000000000000000001033e67e37b32b445580bf4eff","s":"8b748b74000000008b748b748b748b7466e769ad4a16d3dcd87129b8e91d1b4d","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #130: 100-bit r and small s^-1"} +{"x":"4a9f7da2a6c359a16540c271774a6bf1c586357c978256f44a6496d80670968a","y":"c496e73a44563f8d56fbd7bb9e4e3ae304c86f2c508eb777b03924755beb40d4","r":"0000000000000000000000000000000000000000000000000000000000000100","s":"ef9f6ba4d97c09d03178fa20b4aaad83be3cf9cb824a879fec3270fc4b81ef5b","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #131: small r and 100 bit s^-1"} +{"x":"874146432b3cd2c9e26204c0a34136996067d466dde4917a8ff23a8e95ca106b","y":"709b3d50976ef8b385a813bc35f3a20710bdc6edd465e6f43ac4866703a6608c","r":"00000000000000000000000000000000000000062522bbd3ecbe7c39e93e7c25","s":"ef9f6ba4d97c09d03178fa20b4aaad83be3cf9cb824a879fec3270fc4b81ef5b","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #132: 100-bit r and s^-1"} +{"x":"7a736d8e326a9ca62bbe25a34ea4e3633b499a96afa7aaa3fcf3fd88f8e07ede","y":"b3e45879d8622b93e818443a686e869eeda7bf9ae46aa3eafcc48a5934864627","r":"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6324d5","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #133: r and s^-1 are close to n"} +{"x":"e84d9b232e971a43382630f99725e423ec1ecb41e55172e9c69748a03f0d5988","y":"618b15b427ad83363bd041ff75fac98ef2ee923714e7d1dfe31753793c7588d4","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"0000000000000000000000000000000000000000000000000000000000000001","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #134: s == 1"} +{"x":"e84d9b232e971a43382630f99725e423ec1ecb41e55172e9c69748a03f0d5988","y":"618b15b427ad83363bd041ff75fac98ef2ee923714e7d1dfe31753793c7588d4","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"0000000000000000000000000000000000000000000000000000000000000000","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #135: s == 0"} +{"x":"0203736fcb198b15d8d7a0c80f66dddd15259240aa78d08aae67c467de045034","y":"34383438d5041ea9a387ee8e4d4e84b4471b160c6bcf2568b072f8f20e87a996","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #136: point at infinity during verify"} +{"x":"78d844dc7f16b73b1f2a39730da5d8cd99fe2e70a18482384e37dcd2bfea02e1","y":"ed6572e01eb7a8d113d02c666c45ef22d3b9a6a6dea99aa43a8183c26e75d336","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","s":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #137: edge case for signature malleability"} +{"x":"dec6c8257dde94110eacc8c09d2e5789cc5beb81a958b02b4d62da9599a74014","y":"66fae1614174be63970b83f6524421067b06dd6f4e9c56baca4e344fdd690f1d","r":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","s":"7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #138: edge case for signature malleability"} +{"x":"a17f5b75a35ed64623ca5cbf1f91951292db0c23f0c2ea24c3d0cad0988cabc0","y":"83a7a618625c228940730b4fa3ee64faecbb2fc20fdde7c58b3a3f6300424dc6","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #139: u1 == 1"} +{"x":"04ba0cba291a37db13f33bf90dab628c04ec8393a0200419e9eaa1ebcc9fb5c3","y":"1f3a0a0e6823a49b625ad57b12a32d4047970fc3428f0f0049ecf4265dc12f62","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"acd155416a8b77f34089464733ff7cd39c400e9c69af7beb9eac5054ed2ec72c","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #140: u1 == n - 1"} +{"x":"692b6c828e0feed63d8aeaa2b7322f9ccbe8723a1ed39f229f204a434b8900ef","y":"a1f6f6abcb38ea3b8fde38b98c7c271f274af56a8c5628dc3329069ae4dd5716","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #141: u2 == 1"} +{"x":"00cefd9162d13e64cb93687a9cd8f9755ebb5a3ef7632f800f84871874ccef09","y":"543ecbeaf7e8044ef721be2fb5f549e4b8480d2587404ebf7dbbef2c54bc0cb1","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"aaaaaaaa00000000aaaaaaaaaaaaaaaa7def51c91a0fbf034d26872ca84218e1","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #142: u2 == n - 1"} +{"x":"b975183b42551cf52f291d5c1921fd5e12f50c8c85a4beb9de03efa3f0f24486","y":"2243018e6866df922dc313612020311ff21e242ce3fb15bc78c406b25ab43091","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"710f8e3edc7c2d5a3fd23de844002bb949d9f794f6d5405f6d97c1bb03dd2bd2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #143: edge case for u1"} +{"x":"c25f1d166f3e211cdf042a26f8abf6094d48b8d17191d74ed717149274466999","y":"65d06dd6a88abfa49e8b4c5da6bb922851969adf9604b5accfb52a114e77ccdb","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"edffbc270f722c243069a7e5f40335a61a58525c7b4db2e7a8e269274ffe4e1b","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #144: edge case for u1"} +{"x":"8fe5e88243a76e41a004236218a3c3a2d6eee398a23c3a0b008d7f0164cbc0ca","y":"98a20d1bdcf573513c7cfd9b83c63e3a82d40127c897697c86b8cb387af7f240","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"a25adcae105ed7ff4f95d2344e24ee523314c3e178525d007904b68919ba4d53","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #145: edge case for u1"} +{"x":"02148256b530fbc470c7b341970b38243ecee6d5a840a37beca2efb37e8dff2c","y":"c0adbea0882482a7489ca703a399864ba987eeb6ddb738af53a83573473cb30d","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"2e4348c645707dce6760d773de3f3e87346924b2f64bd3dd0297e766b5805ebb","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #146: edge case for u1"} +{"x":"a34db012ce6eda1e9c7375c5fcf3e54ed698e19615124273b3a621d021c76f8e","y":"777458d6f55a364c221e39e1205d5510bb4fbb7ddf08d8d8fdde13d1d6df7f14","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"348c673b07dce3920d773de3f3e87408869e916dbcf797d8f9684fb67753d1dc","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #147: edge case for u1"} +{"x":"b97af3fe78be15f2912b6271dd8a43badb6dd2a1b315b2ce7ae37b4e7778041d","y":"930d71ee1992d2466495c42102d08e81154c305307d1dcd52d0fa4c479b278e7","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"6918ce760fb9c7241aee7bc7e7d0e8110d3d22db79ef2fb1f2d09f6ceea7a3b8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #148: edge case for u1"} +{"x":"81e7198a3c3f23901cedc7a1d6eff6e9bf81108e6c35cd8559139af3135dbcbb","y":"9ef1568530291a8061b90c9f4285eefcba990d4570a4e3b7b737525b5d580034","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"73b3c694391d8eadde3f3e874089464715ac20e4c126bbf6d864d648969f5b5a","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #149: edge case for u1"} +{"x":"ab4d792ca121d1dba39cb9de645149c2ab573e8becc6ddff3cc9960f188ddf73","y":"7f90ba23664153e93262ff73355415195858d7be1315a69456386de68285a3c8","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bb07ac7a86948c2c2989a16db1930ef1b89ce112595197656877e53c41457f28","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #150: edge case for u1"} +{"x":"518412b69af43aae084476a68d59bbde51fbfa9e5be80563f587c9c2652f88ef","y":"2d3b90d25baa6bdb7b0c55e5240a3a98fbc24afed8523edec1c70503fc10f233","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"27e4d82cb6c061dd9337c69bf9332ed3d198662d6f2299443f62c861187db648","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #151: edge case for u1"} +{"x":"a08f14a644b9a935dffea4761ebaf592d1f66fe6cd373aa7f5d370af34f8352d","y":"a54b5bc4025cf335900a914c2934ec2fec7a396d0a7affcad732a5741c7aaaf5","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"e7c5cf3aac2e88923b77850515fff6a12d13b356dfe9ec275c3dd81ae94609a4","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #152: edge case for u1"} +{"x":"ccf2296a6a89b62b90739d38af4ae3a20e9f45715b90044639241061e33f8f8c","y":"aace0046491eeaa1c6e9a472b96d88f4af83e7ff1bb84438c7e058034412ae08","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"c77838df91c1e953e016e10bddffea2317f9fee32bacfe553cede9e57a748f68","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #153: edge case for u1"} +{"x":"94b0fc1525bcabf82b1f34895e5819a06c02b23e04002276e165f962c86e3927","y":"be7c2ab4d0b25303204fb32a1f8292902792225e16a6d2dbfb29fbc89a9c3376","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"8ef071c02383d2a6c02dc217bbffd446730d0318b0425e2586220907f885f97f","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #154: edge case for u1"} +{"x":"5351f37e1de0c88c508527d89882d183ccdcf2efca407edb0627cadfd16de6ec","y":"44b4b57cdf960d32ebcc4c97847eed218425853b5b675eb781b766a1a1300349","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"5668aaa0b545bbf9a044a32399ffbe69ce20074e34d7bdf5cf56282a76976396","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #155: edge case for u1"} +{"x":"748bbafc320e6735cb64019710a269c6c2b5d147bdc831325cb2fb276ac971a6","y":"9d655e9a755bc9d800ad21ee3fd4d980d93a7a49a8c5ccd37005177578f51163","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"d12d6e56882f6c0027cae91a27127728f7fddf478fb4fdc2b65f40a60b0eb952","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #156: edge case for u1"} +{"x":"14b3bbd75c5e1c0c36535a934d4ab85112410b3b90fa97a31c33038964fd85cc","y":"112f7d837f8f9c36b460d636c965a5f818f2b50c5d00fb3f9705561dd6631883","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"7fffffffaaaaaaaaffffffffffffffffe9a2538f37b28a2c513dee40fecbb71a","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #157: edge case for u2"} +{"x":"d823533c04cd8edc6d6f950a8e08ade04a9bafa2f14a590356935671ae9305bf","y":"43178d1f88b6a57a96924c265f0ddb75b58312907b195acb59d7797303123775","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"b62f26b5f2a2b26f6de86d42ad8a13da3ab3cccd0459b201de009e526adf21f2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #158: edge case for u2"} +{"x":"db2b3408b3167d91030624c6328e8ce3ec108c105575c2f3d209b92e654bab69","y":"c34318139c50b0802c6e612f0fd3189d800df7c996d5d7b7c3d6be82836fa258","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bb1d9ac949dd748cd02bbbe749bd351cd57b38bb61403d700686aa7b4c90851e","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #159: edge case for u2"} +{"x":"09179ce7c59225392216453b2ac1e9d178c24837dfae26bc1dd7ab6063852742","y":"5556b42e330289f3b826b2db7a86d19d45c2860a59f2be1ddcc3b691f95a9255","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"66755a00638cdaec1c732513ca0234ece52545dac11f816e818f725b4f60aaf2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #160: edge case for u2"} +{"x":"01959fb8deda56e5467b7e4b214ea4c2d0c2fb29d70ff19b6b1eccebd6568d7e","y":"d9dbd77a918297fd970bff01e1343f6925167db5a14d098a211c39cc3a413398","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"55a00c9fcdaebb6032513ca0234ecfffe98ebe492fdf02e48ca48e982beb3669","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #161: edge case for u2"} +{"x":"567f1fdc387e5350c852b4e8f8ba9d6d947e1c5dd7ccc61a5938245dd6bcab3a","y":"9960bebaf919514f9535c22eaaf0b5812857970e26662267b1f3eb1011130a11","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"ab40193f9b5d76c064a27940469d9fffd31d7c925fbe05c919491d3057d66cd2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #162: edge case for u2"} +{"x":"3499f974ff4ca6bbb2f51682fd5f51762f9dd6dd2855262660b36d46d3e4bec2","y":"f498fae2487807e220119152f0122476c64d4fa46ddce85c4546630f0d5c5e81","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"ca0234ebb5fdcb13ca0234ecffffffffcb0dadbbc7f549f8a26b4408d0dc8600","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #163: edge case for u2"} +{"x":"2c5c01662cf00c1929596257db13b26ecf30d0f3ec4b9f0351b0f27094473426","y":"e986a086060d086eee822ddd2fc744247a0154b57f7a69c51d9fdafa484e4ac7","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff3ea3677e082b9310572620ae19933a9e65b285598711c77298815ad3","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #164: edge case for u2"} +{"x":"91d4cba813a04d86dbae94c23be6f52c15774183be7ba5b2d9f3cf010b160501","y":"900b8adfea6491019a9ac080d516025a541bf4b952b0ad7be4b1874b02fd544a","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"266666663bbbbbbbe6666666666666665b37902e023fab7c8f055d86e5cc41f4","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #165: edge case for u2"} +{"x":"ef7fd0a3a36386638330ecad41e1a3b302af36960831d0210c614b948e8aa124","y":"ef0d6d800e4047d6d3c1be0fdeaf11fcd8cab5ab59c730eb34116e35a8c7d098","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff36db6db7a492492492492492146c573f4c6dfc8d08a443e258970b09","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #166: edge case for u2"} +{"x":"a521dab13cc9152d8ca77035a607fea06c55cc3ca5dbeb868cea92eafe93df2a","y":"7bfb9b28531996635e6a5ccaa2826a406ce1111bdb9c2e0ca36500418a2f43de","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"bfffffff2aaaaaab7fffffffffffffffc815d0e60b3e596ecb1ad3a27cfd49c4","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #167: edge case for u2"} +{"x":"474d58a4eec16e0d565f2187fe11d4e8e7a2683a12f38b4fc01d1237a81a1097","y":"6e55f73bb7cdda46bdb67ef77f6fd2969df2b67920fb5945fde3a517a6ded4cd","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"7fffffff55555555ffffffffffffffffd344a71e6f651458a27bdc81fd976e37","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #168: edge case for u2"} +{"x":"692da5cd4309d9a6e5cb525c37da8fa0879f7b57208cdabbf47d223a5b23a621","y":"40e0daa78cfdd207a7389aaed61738b17fc5fc3e6a5ed3397d2902e9125e6ab4","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"3fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192aa","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #169: edge case for u2"} +{"x":"85689b3e0775c7718a90279f14a8082cfcd4d1f1679274f4e9b8805c570a0670","y":"167fcc5ca734552e09afa3640f4a034e15b9b7ca661ec7ff70d3f240ebe705b1","r":"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd","s":"5d8ecd64a4eeba466815ddf3a4de9a8e6abd9c5db0a01eb80343553da648428f","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #170: edge case for u2"} +{"x":"0158137755b901f797a90d4ca8887e023cb2ef63b2ba2c0d455edaef42cf237e","y":"2a964fc00d377a8592b8b61aafa7a4aaa7c7b9fd2b41d6e0e17bd1ba5677edcd","r":"6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569","s":"f21d907e3890916dc4fa1f4703c1e50d3f54ddf7383e44023a41de562aa18ed8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #171: point duplication during verification"} +{"x":"0158137755b901f797a90d4ca8887e023cb2ef63b2ba2c0d455edaef42cf237e","y":"d569b03ef2c8857b6d4749e550585b5558384603d4be291f1e842e45a9881232","r":"6f2347cab7dd76858fe0555ac3bc99048c4aacafdfb6bcbe05ea6c42c4934569","s":"f21d907e3890916dc4fa1f4703c1e50d3f54ddf7383e44023a41de562aa18ed8","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #172: duplication bug"} +{"x":"38a084ffccc4ae2f8204be2abca9fb8ad4ab283b2aa50f13b6bb2347adabc69c","y":"a699799b77b1cc6dad271e88b899c12931986e958e1f5cf5653dddf7389365e2","r":"0000000000000000000000000000000000000000000000000000000000000001","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #173: point with x-coordinate 0"} +{"x":"664ce273320d918d8bdb2e61201b4549b36b7cdc54e33b84adb6f2c10aac831e","y":"49e68831f18bda2973ac3d76bfbc8c5ee1cceed2dd862e2dc7c915c736cef1f4","r":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aa9","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #175: comparison with point at infinity "} +{"x":"961691a5e960d07a301dbbad4d86247ec27d7089faeb3ddd1add395efff1e0fe","y":"7254622cc371866cdf990d2c5377790e37d1f1519817f09a231bd260a9e78aeb","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #176: extreme value for k and edgecase s"} +{"x":"5d283e13ce8ca60da868e3b0fb33e6b4f1074793274e2928250e71e2aca63e9c","y":"214dc74fa25371fb4d9e506d418ed9a1bfd6d0c8bb6591d3e0f44505a84886ce","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #177: extreme value for k and s^-1"} +{"x":"0fc351da038ae0803bd1d86514ae0462f9f8216551d9315aa9d297f792eef6a3","y":"41c74eed786f2d33da35360ca7aa925e753f00d6077a1e9e5fc339d634019c73","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #178: extreme value for k and s^-1"} +{"x":"a1e34c8f16d138673fee55c080547c2bfd4de7550065f638322bba9430ce4b60","y":"662be9bb512663aa4d7df8ab3f3b4181c5d44a7bdf42436620b7d8a6b81ac936","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #179: extreme value for k and s^-1"} +{"x":"7e1a8a8338d7fd8cf41d322a302d2078a87a23c7186150ed7cda6e52817c1bdf","y":"d0a9135a89d21ce821e29014b2898349254d748272b2d4eb8d59ee34c615377f","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"49249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #180: extreme value for k and s^-1"} +{"x":"5c19fe227a61abc65c61ee7a018cc9571b2c6f663ea33583f76a686f64be078b","y":"7b4a0d734940f613d52bc48673b457c2cf78492490a5cc5606c0541d17b24ddb","r":"7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978","s":"16a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #181: extreme value for k"} +{"x":"db02d1f3421d600e9d9ef9e47419dba3208eed08c2d4189a5db63abeb2739666","y":"e0ed26967b9ada9ed7ffe480827f90a0d210d5fd8ec628e31715e6b24125512a","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"555555550000000055555555555555553ef7a8e48d07df81a693439654210c70","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #182: extreme value for k and edgecase s"} +{"x":"6222d1962655501893c29e441395b6c05711bd3ed5a0ef72cfab338b88229c4b","y":"aaae079cb44a1af070362aaa520ee24cac2626423b0bf81af1c54311d8e2fd23","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"b6db6db6249249254924924924924924625bd7a09bec4ca81bcdd9f8fd6b63cc","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #183: extreme value for k and s^-1"} +{"x":"4ccfa24c67f3def7fa81bc99c70bb0419c0952ba599f4c03361da184b04cdca5","y":"db76b797f7f41d9c729a2219478a7e629728df870800be8cf6ca7a0a82153bfa","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"cccccccc00000000cccccccccccccccc971f2ef152794b9d8fc7d568c9e8eaa7","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #184: extreme value for k and s^-1"} +{"x":"ea1c72c91034036bac71402b6e9ecc4af3dbde7a99dc574061e99fefff9d84da","y":"b7dd057e75b78ac6f56e34eb048f0a9d29d5d055408c90d02bc2ea918c18cb63","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"3333333300000000333333333333333325c7cbbc549e52e763f1f55a327a3aaa","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #185: extreme value for k and s^-1"} +{"x":"c2879a66d86cb20b820b7795da2da62b38924f7817d1cd350d936988e90e79bc","y":"5431a7268ff6931c7a759de024eff90bcb0177216db6fd1f3aaaa11fa3b6a083","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"49249248db6db6dbb6db6db6db6db6db5a8b230d0b2b51dcd7ebf0c9fef7c185","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #186: extreme value for k and s^-1"} +{"x":"ab1c0f273f74abc2b848c75006f2ef3c54c26df27711b06558f455079aee0ba3","y":"df510f2ecef6d9a05997c776f14ad6456c179f0a13af1771e4d6c37fa48b47f2","r":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","s":"16a4502e2781e11ac82cbc9d1edd8c981584d13e18411e2f6e0478c34416e3bb","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #187: extreme value for k"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5","r":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #188: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5","r":"acd155416a8b77f34089464733ff7cd39c400e9c69af7beb9eac5054ed2ec72c","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #189: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a","r":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #190: testing point duplication"} +{"x":"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","y":"b01cbd1c01e58065711814b583f061e9d431cca994cea1313449bf97c840ae0a","r":"acd155416a8b77f34089464733ff7cd39c400e9c69af7beb9eac5054ed2ec72c","s":"249249246db6db6ddb6db6db6db6db6dad4591868595a8ee6bf5f864ff7be0c2","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":false,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #191: testing point duplication"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"a8ea150cb80125d7381c4c1f1da8e9de2711f9917060406a73d7904519e51388","s":"f3ab9fa68bd47973a73b2d40480c2ba50c22c9d76ec217257288293285449b86","hash":"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023","valid":true,"msg":"313233343030","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #269: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"30e782f964b2e2ff065a051bc7adc20615d8c43a1365713c88268822c253bcce","s":"5b16df652aa1ecb2dc8b46c515f9604e2e84cacfa7c6eec30428d2d3f4e08ed5","hash":"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25","valid":true,"msg":"54657374","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #270: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"b292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a","s":"0177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2","hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","valid":true,"msg":"","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #271: pseudorandom signature"} +{"x":"04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5","y":"87d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d","r":"986e65933ef2ed4ee5aada139f52b70539aaf63f00a91f29c69178490d57fb71","s":"3dafedfb8da6189d372308cbf1489bbbdabf0c0217d1c0ff0f701aaa7a694b9c","hash":"de47c9b27eb8d300dbb5f2c353e632c393262cf06340c4fa7f1b40c4cbd36f90","valid":true,"msg":"0000000000000000000000000000000000000000","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #272: pseudorandom signature"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"d434e262a49eab7781e353a3565e482550dd0fd5defa013c7f29745eff3569f1","s":"9b0c0a93f267fb6052fd8077be769c2b98953195d7bc10de844218305c6ba17a","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #288: x-coordinate of the public key has many trailing 0's"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"0fe774355c04d060f76d79fd7a772e421463489221bf0a33add0be9b1979110b","s":"500dcba1c69a8fbd43fa4f57f743ce124ca8b91a1f325f3fac6181175df55737","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #289: x-coordinate of the public key has many trailing 0's"} +{"x":"4f337ccfd67726a805e4f1600ae2849df3807eca117380239fbd816900000000","y":"ed9dea124cc8c396416411e988c30f427eb504af43a3146cd5df7ea60666d685","r":"bb40bf217bed3fb3950c7d39f03d36dc8e3b2cd79693f125bfd06595ee1135e3","s":"541bf3532351ebb032710bdb6a1bf1bfc89a1e291ac692b3fa4780745bb55677","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #290: x-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"664eb7ee6db84a34df3c86ea31389a5405badd5ca99231ff556d3e75a233e73a","s":"59f3c752e52eca46137642490a51560ce0badc678754b8f72e51a2901426a1bd","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #291: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"4cd0429bbabd2827009d6fcd843d4ce39c3e42e2d1631fd001985a79d1fd8b43","s":"9638bf12dd682f60be7ef1d0e0d98f08b7bca77a1a2b869ae466189d2acdabe3","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #292: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"84fa174d791c72bf2ce3880a8960dd2a7c7a1338a82f85a9e59cdbde80000000","r":"e56c6ea2d1b017091c44d8b6cb62b9f460e3ce9aed5e5fd41e8added97c56c04","s":"a308ec31f281e955be20b457e463440b4fcf2b80258078207fc1378180f89b55","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #293: y-coordinate of the public key has many trailing 0's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"1158a08d291500b4cabed3346d891eee57c176356a2624fb011f8fbbf3466830","s":"228a8c486a736006e082325b85290c5bc91f378b75d487dda46798c18f285519","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #294: y-coordinate of the public key has many trailing 1's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"b1db9289649f59410ea36b0c0fc8d6aa2687b29176939dd23e0dde56d309fa9d","s":"3e1535e4280559015b0dbd987366dcf43a6d1af5c23c7d584e1c3f48a1251336","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #295: y-coordinate of the public key has many trailing 1's"} +{"x":"3cf03d614d8939cfd499a07873fac281618f06b8ff87e8015c3f497265004935","y":"7b05e8b186e38d41d31c77f5769f22d58385ecc857d07a561a6324217fffffff","r":"b7b16e762286cb96446aa8d4e6e7578b0a341a79f2dd1a220ac6f0ca4e24ed86","s":"ddc60a700a139b04661c547d07bbb0721780146df799ccf55e55234ecb8f12bc","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #296: y-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"d82a7c2717261187c8e00d8df963ff35d796edad36bc6e6bd1c91c670d9105b4","s":"3dcabddaf8fcaa61f4603e7cbac0f3c0351ecd5988efb23f680d07debd139929","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #297: x-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"5eb9c8845de68eb13d5befe719f462d77787802baff30ce96a5cba063254af78","s":"2c026ae9be2e2a5e7ca0ff9bbd92fb6e44972186228ee9a62b87ddbe2ef66fb5","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #298: x-coordinate of the public key has many trailing 1's"} +{"x":"2829c31faa2e400e344ed94bca3fcd0545956ebcfe8ad0f6dfa5ff8effffffff","y":"a01aafaf000e52585855afa7676ade284113099052df57e7eb3bd37ebeb9222e","r":"96843dd03c22abd2f3b782b170239f90f277921becc117d0404a8e4e36230c28","s":"f2be378f526f74a543f67165976de9ed9a31214eb4d7e6db19e1ede123dd991d","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #299: x-coordinate of the public key has many trailing 1's"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"766456dce1857c906f9996af729339464d27e9d98edc2d0e3b760297067421f6","s":"402385ecadae0d8081dccaf5d19037ec4e55376eced699e93646bfbbf19d0b41","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #300: x-coordinate of the public key is large"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"c605c4b2edeab20419e6518a11b2dbc2b97ed8b07cced0b19c34f777de7b9fd9","s":"edf0f612c5f46e03c719647bc8af1b29b2cde2eda700fb1cff5e159d47326dba","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #301: x-coordinate of the public key is large"} +{"x":"fffffff948081e6a0458dd8f9e738f2665ff9059ad6aac0708318c4ca9a7a4f5","y":"5a8abcba2dda8474311ee54149b973cae0c0fb89557ad0bf78e6529a1663bd73","r":"d48b68e6cabfe03cf6141c9ac54141f210e64485d9929ad7b732bfe3b7eb8a84","s":"feedae50c61bd00e19dc26f9b7e2265e4508c389109ad2f208f0772315b6c941","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #302: x-coordinate of the public key is large"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"b7c81457d4aeb6aa65957098569f0479710ad7f6595d5874c35a93d12a5dd4c7","s":"b7961a0b652878c2d568069a432ca18a1a9199f2ca574dad4b9e3a05c0a1cdb3","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #303: x-coordinate of the public key is small"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"6b01332ddb6edfa9a30a1321d5858e1ee3cf97e263e669f8de5e9652e76ff3f7","s":"5939545fced457309a6a04ace2bd0f70139c8f7d86b02cb1cc58f9e69e96cd5a","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #304: x-coordinate of the public key is small"} +{"x":"00000003fa15f963949d5f03a6f5c7f86f9e0015eeb23aebbff1173937ba748e","y":"1099872070e8e87c555fa13659cca5d7fadcfcb0023ea889548ca48af2ba7e71","r":"efdb884720eaeadc349f9fc356b6c0344101cd2fd8436b7d0e6a4fb93f106361","s":"f24bee6ad5dc05f7613975473aadf3aacba9e77de7d69b6ce48cb60d8113385d","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #305: x-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"31230428405560dcb88fb5a646836aea9b23a23dd973dcbe8014c87b8b20eb07","s":"0f9344d6e812ce166646747694a41b0aaf97374e19f3c5fb8bd7ae3d9bd0beff","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #306: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"caa797da65b320ab0d5c470cda0b36b294359c7db9841d679174db34c4855743","s":"cf543a62f23e212745391aaf7505f345123d2685ee3b941d3de6d9b36242e5a0","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #307: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"000000001352bb4a0fa2ea4cceb9ab63dd684ade5a1127bcf300a698a7193bc2","r":"7e5f0ab5d900d3d3d7867657e5d6d36519bc54084536e7d21c336ed800185945","s":"9450c07f201faec94b82dfb322e5ac676688294aad35aa72e727ff0b19b646aa","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #308: y-coordinate of the public key is small"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"d7d70c581ae9e3f66dc6a480bf037ae23f8a1e4a2136fe4b03aa69f0ca25b356","s":"89c460f8a5a5c2bbba962c8a3ee833a413e85658e62a59e2af41d9127cc47224","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #309: y-coordinate of the public key is large"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"341c1b9ff3c83dd5e0dfa0bf68bcdf4bb7aa20c625975e5eeee34bb396266b34","s":"72b69f061b750fd5121b22b11366fad549c634e77765a017902a67099e0a4469","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #310: y-coordinate of the public key is large"} +{"x":"bcbb2914c79f045eaa6ecbbc612816b3be5d2d6796707d8125e9f851c18af015","y":"fffffffeecad44b6f05d15b33146549c2297b522a5eed8430cff596758e6c43d","r":"70bebe684cdcb5ca72a42f0d873879359bd1781a591809947628d313a3814f67","s":"aec03aca8f5587a4d535fa31027bbe9cc0e464b1c3577f4c2dcde6b2094798a9","hash":"2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91","valid":true,"msg":"4d657373616765","comment":"wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #311: y-coordinate of the public key is large"} \ No newline at end of file