diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache new file mode 100644 index 0000000..8c415f8 --- /dev/null +++ b/.php-cs-fixer.cache @@ -0,0 +1 @@ +{"php":"8.3.6","version":"3.95.1:v3.95.1#a9727678fbd12997f1d9de8f4a37824ed9df1065","indent":" ","lineEnding":"\n","rules":{"array_syntax":{"syntax":"short"},"binary_operator_spaces":{"default":"single_space","operators":{"=":"align","=>":"align"}},"blank_line_after_namespace":true,"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["break","continue","declare","return","throw","try"]},"braces":true,"cast_spaces":true,"class_attributes_separation":{"elements":{"const":"one","method":"one","property":"one"}},"class_definition":true,"concat_space":{"spacing":"none"},"constant_case":{"case":"lower"},"declare_equal_normalize":true,"declare_strict_types":true,"echo_tag_syntax":{"format":"long"},"elseif":true,"encoding":true,"final_internal_class":true,"full_opening_tag":true,"fully_qualified_strict_types":true,"function_declaration":true,"function_typehint_space":true,"heredoc_to_nowdoc":true,"include":true,"increment_style":{"style":"post"},"indentation_type":true,"linebreak_after_opening_tag":true,"line_ending":true,"lowercase_cast":true,"lowercase_keywords":true,"lowercase_static_reference":true,"magic_method_casing":true,"magic_constant_casing":true,"method_argument_space":true,"multiline_whitespace_before_semicolons":{"strategy":"no_multi_line"},"native_function_casing":true,"new_with_braces":true,"no_alias_functions":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_closing_tag":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_blank_lines":{"tokens":["extra","throw","use","use_trait"]},"no_leading_import_slash":true,"no_leading_namespace_whitespace":true,"no_mixed_echo_print":{"use":"echo"},"no_multiline_whitespace_around_double_arrow":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_after_function_name":true,"no_spaces_around_offset":{"positions":["inside"]},"no_spaces_inside_parenthesis":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"no_unneeded_control_parentheses":{"statements":["break","clone","continue","echo_print","return","switch_case","yield"]},"no_unreachable_default_argument_value":true,"no_unused_imports":true,"no_useless_else":true,"no_useless_return":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"not_operator_with_successor_space":true,"object_operator_without_whitespace":true,"ordered_class_elements":true,"ordered_imports":{"sort_algorithm":"alpha"},"php_unit_strict":true,"php_unit_test_class_requires_covers":true,"phpdoc_add_missing_param_annotation":true,"phpdoc_indent":true,"phpdoc_inline_tag_normalizer":true,"phpdoc_no_access":true,"phpdoc_no_package":true,"phpdoc_no_useless_inheritdoc":true,"phpdoc_order":true,"phpdoc_scalar":true,"phpdoc_single_line_var_spacing":true,"phpdoc_summary":true,"phpdoc_to_comment":{"ignored_tags":["var"]},"phpdoc_trim":true,"phpdoc_types":true,"phpdoc_var_without_name":true,"psr_autoloading":true,"self_accessor":true,"semicolon_after_instruction":true,"short_scalar_cast":true,"simplified_null_return":true,"single_blank_line_at_eof":true,"single_blank_line_before_namespace":true,"single_class_element_per_statement":{"elements":["const","property"]},"single_import_per_statement":true,"single_line_after_imports":true,"single_line_comment_style":{"comment_types":["hash"]},"single_quote":true,"single_trait_insert_per_statement":true,"space_after_semicolon":true,"standardize_not_equals":true,"strict_comparison":true,"strict_param":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"ternary_operator_spaces":true,"trailing_comma_in_multiline":{"elements":["arrays"]},"trim_array_spaces":true,"unary_operator_spaces":true,"visibility_required":{"elements":["property","method","const"]},"whitespace_after_comma_in_array":true},"ruleCustomisationPolicyVersion":"null-policy","hashes":{"src\/Binary\/Hex\/Writer.php":"590df3f3343c052d96d3cbbeb317f265","src\/Binary\/Buffer\/Writer\/Buffer.php":"80ab7029c26d83449a3529f4cee7a648","src\/Binary\/Buffer\/Writer\/Concerns\/Hex.php":"320937c99c2d66a2fe5c97396a994921","src\/Binary\/Buffer\/Writer\/Concerns\/Integer.php":"1f80863a79db7a412ed78fd647ff1cdf","src\/Binary\/Buffer\/Writer\/Concerns\/UnsignedInteger.php":"2ffba9fbbc552cb15166b7c47e22cd0e","src\/Binary\/Buffer\/Writer\/Concerns\/Generic.php":"76f295b93cc3d1327bf799f57d5a978c","src\/Binary\/Buffer\/Reader\/Buffer.php":"ec09343504cca539cf6bf91aace82464","src\/Binary\/Buffer\/Reader\/Concerns\/Hex.php":"3442407232a6093352c8e2b3146169f5","src\/Binary\/Buffer\/Reader\/Concerns\/Integer.php":"978f791a745c7b99d81032ef7f182558","src\/Binary\/Buffer\/Reader\/Concerns\/UnsignedInteger.php":"6a2f2ea4c5839184a7715dc633a504bd","src\/Exceptions\/InvalidUsernameException.php":"d392da166f80b3be9bdf4ba13d1e7b89","src\/Helpers.php":"90816e6ab5e44ebcb4c31770b610fa3b","src\/Enums\/ContractAbiType.php":"6aeea79e287ad76d65dc4ad0fcdf10eb","src\/Enums\/AbiFunction.php":"07ae22bd4ede5b6e9f83eb49a1bbd463","src\/Enums\/ContractAddresses.php":"06e2508d6640ce4572565eadbd390a20","src\/Identities\/Address.php":"83f02a9f2e101ce9ed1748bd3c0a0aab","src\/Identities\/PrivateKey.php":"a4bd870539d13f97a21e714608310804","src\/Identities\/WIF.php":"60dd95da09bb6c240acd02cd3f52a6b8","src\/Identities\/PublicKey.php":"2deb4baddcc512f012a06ce5f3b39387","src\/Binary\/Hex\/Reader.php":"e28448b92fadb2979e1db484a6afca8d","src\/ByteBuffer\/Concerns\/Writes\/Hex.php":"169cc84b5e39930c7e168d7bdbbcd37d","src\/ByteBuffer\/Concerns\/Writes\/Strings.php":"ba4ebf613b130f41b0a531dbd07c43c5","src\/ByteBuffer\/Concerns\/Writes\/Integer.php":"6f717766d8775b349f0e474902f66511","src\/ByteBuffer\/Concerns\/Writes\/Floats.php":"f3797170755677f4776f1cefbda60cb6","src\/ByteBuffer\/Concerns\/Writes\/UnsignedInteger.php":"68a9620949ef00f0b9676f2a1433d849","src\/ByteBuffer\/Concerns\/Reads\/Hex.php":"f3cc0a816b6e9469740bf59575363516","src\/ByteBuffer\/Concerns\/Reads\/Strings.php":"17238cbe09b4b870fa66b5704709f18e","src\/ByteBuffer\/Concerns\/Reads\/Integer.php":"9fa6cb50cebf03b7bf00e3b5337d9873","src\/ByteBuffer\/Concerns\/Reads\/Floats.php":"056b5c5b629a9fd0231becaded2f6973","src\/ByteBuffer\/Concerns\/Reads\/UnsignedInteger.php":"3d29cc54a05f7c6a02973e5618f821ae","src\/Utils\/RlpEncoder.php":"3f12a6053f27f931d0fabbfb91e1a7cf","src\/Utils\/TransactionUtils.php":"6e5ec26cbe4b2125c59a37331083173a","src\/Utils\/TransactionTypeIdentifier.php":"b89b96a26412691b042f4b2f1586a01f","src\/Utils\/Abi\/ArgumentDecoder.php":"6430cb971aa8e5927b62270afdec0af6","src\/Utils\/UnitConverter.php":"d716c75d97fb21408dd1b2d86d18c75d","src\/Utils\/TransactionEncoder.php":"439eaab92539814629cd8e216634a937","src\/Utils\/AbiEncoder.php":"e0edf2b073a0b0efe07896731846535c","src\/ByteBuffer\/LengthMap.php":"2f62d17297dc7387a39466df38b8649b","src\/ByteBuffer\/Concerns\/Transformable.php":"3d1f8aa43854c9417538e51dfdcd106f","src\/ByteBuffer\/Concerns\/Positionable.php":"86e5bc94fc7389aed28ba6fec9d7d2c2","src\/Binary\/Integer\/Reader.php":"fbe1a1af3821a1c2ee79e996a254ef2a","src\/Binary\/Integer\/Writer.php":"e6dbdb22282670b0547c66202cf25abf","src\/Binary\/UnsignedInteger\/Reader.php":"e9d87277e9f0e8cd6f3a63b6caa95ad2","src\/Binary\/UnsignedInteger\/Writer.php":"c0443907d9a5c9b2c027eca99ae775f5","src\/Utils\/Address.php":"410b85d6c0ba3764293463b48c03da91","src\/Utils\/AbiBase.php":"772be753e59f052101bc7616ecc2ca6d","src\/Utils\/RlpDecoder.php":"3fbea35725a5194184db4c650239418c","src\/Utils\/AbiDecoder.php":"8bfbd3752176ffb1a2321f72f4f01dff","src\/Utils\/Slot.php":"9674e711b193645b0b769514ab1d5907","src\/Utils\/Message.php":"6dc3cf7e0fe73c86d1eaa54ae0052ce7","src\/ByteBuffer\/Concerns\/Initialisable.php":"96a9455179a83ec00139d937bcd58626","src\/ByteBuffer\/Concerns\/Sizeable.php":"6b03f909020b0d15bc4c35256d85c896","src\/ByteBuffer\/Concerns\/Offsetable.php":"68179b59de54fe5a6233eb7111f6dc79","src\/ByteBuffer\/Concerns\/Readable.php":"518d72f8d0f926461b3248336640abae","src\/ByteBuffer\/Concerns\/Writeable.php":"6970a6fb60370c572f3a3febe6c3df09","src\/ByteBuffer\/ByteBuffer.php":"466a031832de383903af0251fc88be93","src\/ByteBuffer\/ByteOrder.php":"36dff8aac67cf33c653ba15e906e2680","src\/Transactions\/Builder\/EvmCallBuilder.php":"60eeff1cdc6dc59528d216db71211e49","src\/Transactions\/Builder\/TransferBuilder.php":"96ff6d1443e60e6c7ae5a37ed400a62f","src\/Transactions\/Builder\/ValidatorResignationBuilder.php":"ca8561048ac8aa2a0d623b7c327a0afd","src\/Transactions\/Builder\/UsernameRegistrationBuilder.php":"c9bb1a7376cadda5152abd5e46f0be8c","src\/Transactions\/Builder\/AbstractTransactionBuilder.php":"c984b9b1efeb4b7e389e9b01a24b5628","src\/Transactions\/Builder\/TokenTransferBuilder.php":"5a48ac7df4a614009c4b063343157ee0","src\/Transactions\/Builder\/UnvoteBuilder.php":"a37b3c38a9ce5f663579e3ce28e16ff3","src\/Transactions\/Builder\/TokenApproveBuilder.php":"c95653c20511eb4e9ba309260491a34d","src\/Transactions\/Builder\/UsernameResignationBuilder.php":"44ddc136b094777b3fb105fef647db11","src\/Transactions\/Builder\/MultipaymentBuilder.php":"562c803fa9e19a6873951f7cd1bad1c8","src\/Transactions\/Builder\/VoteBuilder.php":"02426dd1b4042447e25a64eb78188fb7","src\/Transactions\/Builder\/ValidatorRegistrationBuilder.php":"306d0ae7b7b9c49660711707e22a95f1","src\/Transactions\/Types\/UsernameRegistration.php":"485b52c32da8b62826617708f3b4a6ec","src\/Transactions\/Types\/Vote.php":"90972b6a028a7652351655a1c1b08b34","src\/Transactions\/Types\/Multipayment.php":"b10ca169d3d37058ad7b940b48d11a8a","src\/Transactions\/Types\/EvmCall.php":"df3aa5b419b200b9eac9d5fc87d240c8","src\/Transactions\/Types\/ValidatorResignation.php":"090882c106dfa298a956bd8eeb49c447","src\/Transactions\/Types\/AbstractTransaction.php":"60222b9229ae21c646b2e30cc38b6871","src\/Transactions\/Types\/Transfer.php":"4d3a16aa308ccf80758b212eca33b669","src\/Transactions\/Types\/ValidatorRegistration.php":"676a366a714e258742b5d0bac8927ebc","src\/Transactions\/Types\/Unvote.php":"56b3c9b921f038639f4eac0d6239e437","src\/Transactions\/Types\/UsernameResignation.php":"68848e1cd4b4d341aa7ff831481ffe31","src\/Transactions\/Serializer.php":"54487af37809b3c134efdce4e26ed1b2","src\/Networks\/Mainnet.php":"3acffe72b51707db16ad4b1a78f050b1","src\/Networks\/AbstractNetwork.php":"5b1cb5aa9830faf93a7f68023614dc1c","src\/Networks\/Testnet.php":"60f72744f4691e2da852b66e9d85a5f0","tests\/Unit\/HelpersTest.php":"40826b23445858a4968985a8c27a7da0","tests\/Unit\/Enums\/AbiFunctionTest.php":"d9ff7604b7be95adad992489c7b0f3dc","tests\/Unit\/Identities\/PrivateKeyTest.php":"19275c459ca01885ae4bf73ffcbecd33","tests\/Unit\/Identities\/PublicKeyTest.php":"e406835540aa170e6e27d24a2a36c09a","tests\/Unit\/Identities\/AddressTest.php":"0e0b7cfefdec532df286f52ce9ddee0f","tests\/Unit\/Identities\/WIFTest.php":"5619ab75730edbb32603355767e5ff70","tests\/Unit\/Binary\/Hex\/WriterTest.php":"85dad01bc8693af66bc55c40a2e603c5","tests\/Unit\/Binary\/Hex\/ReaderTest.php":"f179cd6f729f0d866518038803446228","tests\/Unit\/Binary\/Buffer\/Writer\/BufferTest.php":"6372984efaf7d2a378a7c2ebc3019f3a","tests\/Unit\/Binary\/Buffer\/Reader\/BufferTest.php":"6c6996473bf7c7d8592e3639f5326dda","tests\/Unit\/Binary\/Integer\/WriterTest.php":"64a1f07dc16c4faf2c06a3e5092a107d","tests\/Unit\/Binary\/Integer\/ReaderTest.php":"599fef4860548866a39f64e3dbb44e7d","tests\/Unit\/Binary\/UnsignedInteger\/WriterTest.php":"c10138f97a2b9f34c80d6feae77e77cc","tests\/Unit\/Binary\/UnsignedInteger\/ReaderTest.php":"c88736b794a6320cae58e6554b2cd8bc","tests\/Unit\/Utils\/TransactionEncoderTest.php":"05a4891b1879354a9d69a8bc1b5cb827","tests\/Unit\/Utils\/TransactionUtilsTest.php":"01a1855eacb299b74a997d7dd5987774","tests\/Unit\/Utils\/AddressTest.php":"e2851e599dd5b442cbe83e9c1f28e4b9","tests\/Unit\/ByteBuffer\/Concerns\/SizeableTest.php":"d1a553d36f3fec95b857c839e2d834cb","tests\/Unit\/ByteBuffer\/Concerns\/Writes\/IntegerTest.php":"e5124461e7a97a3e2d78e5b6f5469991","tests\/Unit\/ByteBuffer\/Concerns\/Writes\/HexTest.php":"1abfe709a9e787f7b4e4718d5af0e65c","tests\/Unit\/ByteBuffer\/Concerns\/Writes\/UnsignedIntegerTest.php":"4f2ed9775cd92f3d136d9d6b1cd8f25c","tests\/Unit\/ByteBuffer\/Concerns\/Writes\/FloatsTest.php":"9b45e3276289bb0c44faf94326d6ff76","tests\/Unit\/ByteBuffer\/Concerns\/Writes\/StringsTest.php":"6f591e8733550f1ad0d231f7809ad0a5","tests\/Unit\/ByteBuffer\/Concerns\/Reads\/IntegerTest.php":"3b113ff1f80a9e15ab7af1a29161259b","tests\/Unit\/ByteBuffer\/Concerns\/Reads\/HexTest.php":"01aa9304919af4fa3fa6aaef2f897679","tests\/Unit\/ByteBuffer\/Concerns\/Reads\/UnsignedIntegerTest.php":"cddc6997c7daf4c494b7a65b22823bc3","tests\/Unit\/ByteBuffer\/Concerns\/Reads\/FloatsTest.php":"e4d5200763a77c3993047247d59b3488","tests\/Unit\/Utils\/AbiEncoderTest.php":"8e9601a7576c4e0590f9508267464ff6","tests\/Unit\/Utils\/RlpEncoderTest.php":"6710ec96e9603dbe073181e095674027","tests\/Unit\/Utils\/UnitConverterTest.php":"b4dfb4b2bdeac414b9c85b35a8e09d8c","tests\/Unit\/Utils\/AbiDecoderTest.php":"aff7a7433e0b9b27b4b3f724609968a3","tests\/Unit\/Utils\/SlotTest.php":"ed89ae0182409d977a4faab9ca1eea95","tests\/Unit\/Utils\/RlpDecoderTest.php":"12f50e696926077dbbc1f005cbae2ef2","tests\/Unit\/Utils\/TransactionTypeIdentifierTest.php":"f7ecc6168bdbf6b4223e0eb3b9da7a91","tests\/Unit\/Utils\/MessageTest.php":"71efee57f29dceda4e36e133169c5683","tests\/Unit\/Utils\/Abi\/ArgumentDecoderTest.php":"9e1fda36ecf2cde01b7db5c85658bc24","tests\/Unit\/ByteBuffer\/ByteBufferTest.php":"34237362a8d54d9c4d1610d59fedf7f8","src\/Transactions\/Deserializer.php":"5d77b8f779a3485de6caf6a08d4d5f3b","src\/Configuration\/Network.php":"d908336264d1b5c789e42fe7ba0cfe2c","src\/BLS\/HashToCurve\/G2HashToCurve.php":"104f044fbd0bfc2d871412caf6284306","src\/BLS\/ProofOfPossession.php":"f27d847ffcb5db3d5179367adadcb018","src\/BLS\/Fields\/Fp2.php":"7685c72b29900bef127170b812134086","src\/BLS\/Fields\/Fp.php":"415f741a7ae6e45436e54f3258b95363","src\/BLS\/EIP2333.php":"8ae983f54821a7d04a215ab109f240d8","src\/BLS\/Curves\/G2.php":"69e7f11b35b6f66c22265d1242b4cbed","src\/BLS\/Curves\/G1.php":"7dc863fe9fc87415120143b23bf3172b","src\/Networks\/NetworkInterface.php":"b0aff2a147eb231da8cee50012841830","tests\/Unit\/ByteBuffer\/Concerns\/Reads\/StringsTest.php":"344d7500a1776339f787c9f56be5b580","tests\/Unit\/ByteBuffer\/Concerns\/TransformableTest.php":"6230c022bbcada03e9e336e532b34b55","tests\/Unit\/ByteBuffer\/Concerns\/PositionableTest.php":"10004a8bf4ed76dc108dd5ae3db7596d","tests\/Unit\/ByteBuffer\/Concerns\/OffsetableTest.php":"6888874a372bccc480c2c7ebee35c4cf","tests\/Unit\/ByteBuffer\/Concerns\/InitialisableTest.php":"f9e38c617dea3bb087550a78fa333d2c","tests\/Unit\/ByteBuffer\/LengthMapTest.php":"7e8c04fdf23a09c06c3c77aa7dfb037a","tests\/Unit\/Transactions\/Builder\/TokenApproveBuilderTest.php":"eefe09a0b5c68542c7a33d3c2250b94b","tests\/Unit\/Transactions\/Builder\/TransferBuilderTest.php":"90a7ca6fed95fde81fc4f0d053264003","tests\/Unit\/Transactions\/Builder\/ValidatorResignationBuilderTest.php":"c744298864255a9851f85878c91fd5a6","tests\/Unit\/Transactions\/Builder\/UsernameResignationBuilderTest.php":"c3443fe93b7b10b85f33b6e3e5b6477a","tests\/Unit\/Transactions\/Builder\/TokenTransferBuilderTest.php":"d0afe43a3065f8f6c279deb940930ef5","tests\/Unit\/Transactions\/Builder\/UnvoteBuilderTest.php":"eed8e8215db82abd4a5c2994453b9772","tests\/Unit\/Transactions\/Builder\/MultipaymentBuilderTest.php":"f6aded1988aacb3c15a70885340e08f7","tests\/Unit\/Transactions\/Builder\/EvmCallBuilderTest.php":"1d95fae15d239d2eea1ab245609397da","tests\/Unit\/Transactions\/Builder\/ValidatorRegistrationBuilderTest.php":"444cfc7a77f402d135bc0f5ac7d6d6a5","tests\/Unit\/Transactions\/Builder\/UsernameRegistrationBuilderTest.php":"baba0df21fdb5fdedf41084b35c02cb9","tests\/Unit\/Transactions\/Builder\/VoteBuilderTest.php":"d3ec709c1e626422fa8a86eb833ae0ea","tests\/Unit\/Transactions\/Types\/TransferTest.php":"71110444ac25ca571c6dc6f855625c13","tests\/Unit\/Transactions\/Types\/ValidatorResignationTest.php":"1817a13685810de64b15df1630b11e5d","tests\/Unit\/Transactions\/Types\/EvmCallTest.php":"b37cff6589fa63bc43a196626853c208","tests\/Analysis\/AnalysisTest.php":"3dd50256922f683ee5ac773e20397598","tests\/Unit\/BLS\/EIP2333Test.php":"a7cbb6d601453304110e6e429ba9488b","tests\/Unit\/BLS\/ProofOfPossessionTest.php":"3e807b274f0d61f6f26ad98402163206","tests\/Unit\/Networks\/MainnetTest.php":"372a7750ae834599a0088b09a4fac760","tests\/Unit\/Networks\/TestnetTest.php":"c8dba3e353c84037c78d558548760872","tests\/Pest.php":"f56068e0b3ed7b33d7200c0d7684d2b4","tests\/Helpers.php":"362fa87b858b91ed6cb4112224fba1c2","tests\/TestCase.php":"4133b24901762dc409bb9a111c8c4853","tests\/Concerns\/Serialize.php":"5011734a689b042840e8c277c42b9a36","tests\/Concerns\/Deserialize.php":"d59555dc433a75a3e75d4483219c5e41","tests\/Concerns\/Fixtures.php":"db5b42eaf5cf381b51f8440c66669efd","tests\/Unit\/Transactions\/Types\/UnvoteTest.php":"9b57057eb1b0c17e7c783506a96c287a","tests\/Unit\/Transactions\/Types\/ValidatorRegistrationTest.php":"7b8b5c37a358ed4958a9950ca559df6e","tests\/Unit\/Transactions\/Types\/MultipaymentTest.php":"27d691ef2e4da83f8f4ff09e4c31c702","tests\/Unit\/Transactions\/Types\/UsernameRegistrationTest.php":"b5200bbac887cdbafd894d1883a593eb","tests\/Unit\/Transactions\/Types\/UsernameResignationTest.php":"69477c3478261dfdf7d4fe4eb96e0cd6","tests\/Unit\/Transactions\/Types\/VoteTest.php":"f87adb812093d3b257edae1778428c3a","tests\/Unit\/Transactions\/DeserializerTest.php":"c69a20d6f44306c0f6c136d0c6dc322a","tests\/Unit\/Transactions\/TransactionTest.php":"251c1ec6920f5aed952bfb1297ef1b1f","tests\/Unit\/Transactions\/SerializerTest.php":"6bef82d199db0b3991c9004f55074879","tests\/Unit\/Configuration\/NetworkTest.php":"fda057f8eb08ceb6c89e26e44b1acba1","src\/Identities\/LegacyAddress.php":"ddad24a8b70ed876c05032137d42b56a","src\/Transactions\/Builder\/BatchTransferBuilder.php":"61667bcef4d1bbdfce39d78721dbccc6","tests\/Unit\/Identities\/LegacyAddressTest.php":"061562efb8005bac42f41899d70f6a8e","tests\/Unit\/Transactions\/Builder\/BatchTransferBuilderTest.php":"c0961fd9bb26d6d6b0f23f2999c4ac5a"}} \ No newline at end of file diff --git a/composer.json b/composer.json index 8f552f4..4fe874d 100755 --- a/composer.json +++ b/composer.json @@ -21,7 +21,8 @@ "brick/math": "^0.14.2", "kornrunner/keccak": "^1.1", "protonlabs/bitcoin": "^1.0", - "simplito/elliptic-php": "^1.0" + "simplito/elliptic-php": "^1.0", + "ext-gmp": "*" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.59", diff --git a/src/BLS/Curves/G1.php b/src/BLS/Curves/G1.php new file mode 100644 index 0000000..ec78b98 --- /dev/null +++ b/src/BLS/Curves/G1.php @@ -0,0 +1,193 @@ +x = $x; + $this->y = $y; + $this->z = $z; + } + + public static function generator(): self + { + return new self(Fp::fromHex(self::GX), Fp::fromHex(self::GY), Fp::one()); + } + + public static function identity(): self + { + return new self(Fp::zero(), Fp::one(), Fp::zero()); + } + + public function isIdentity(): bool + { + return $this->z->isZero(); + } + + // ------------------------------------------------------------------------- + // Point doubling (dbl-2009-l, a=0) + // ------------------------------------------------------------------------- + + public function double(): self + { + if ($this->isIdentity()) { + return self::identity(); + } + + $X = $this->x; + $Y = $this->y; + $Z = $this->z; + + $A = $X->square(); + $B = $Y->square(); + $C = $B->square(); + $D = $X->add($B)->square()->sub($A)->sub($C)->mul(Fp::fromInt(2)); + $E = $A->mul(Fp::fromInt(3)); + $F = $E->square(); + $X3 = $F->sub($D->mul(Fp::fromInt(2))); + $Y3 = $E->mul($D->sub($X3))->sub($C->mul(Fp::fromInt(8))); + $Z3 = $Y->mul($Z)->mul(Fp::fromInt(2)); + + return new self($X3, $Y3, $Z3); + } + + // ------------------------------------------------------------------------- + // Point addition (add-2007-bl, handles mixed/projective) + // ------------------------------------------------------------------------- + + public function add(self $other): self + { + if ($this->isIdentity()) { + return $other; + } + if ($other->isIdentity()) { + return $this; + } + + $X1 = $this->x; + $Y1 = $this->y; + $Z1 = $this->z; + $X2 = $other->x; + $Y2 = $other->y; + $Z2 = $other->z; + + $Z1Z1 = $Z1->square(); + $Z2Z2 = $Z2->square(); + $U1 = $X1->mul($Z2Z2); + $U2 = $X2->mul($Z1Z1); + $S1 = $Y1->mul($Z2)->mul($Z2Z2); + $S2 = $Y2->mul($Z1)->mul($Z1Z1); + $H = $U2->sub($U1); + $r = $S2->sub($S1)->mul(Fp::fromInt(2)); + + // If H == 0 and r == 0: both points are equal, use double + if ($H->isZero()) { + if ($r->isZero()) { + return $this->double(); + } + + return self::identity(); // opposite points + } + + $I = $H->mul(Fp::fromInt(2))->square(); + $J = $H->mul($I); + $V = $U1->mul($I); + $X3 = $r->square()->sub($J)->sub($V->mul(Fp::fromInt(2))); + $Y3 = $r->mul($V->sub($X3))->sub($S1->mul($J)->mul(Fp::fromInt(2))); + $Z3 = $Z1->add($Z2)->square()->sub($Z1Z1)->sub($Z2Z2)->mul($H); + + return new self($X3, $Y3, $Z3); + } + + public function neg(): self + { + return new self($this->x, $this->y->neg(), $this->z); + } + + // ------------------------------------------------------------------------- + // Scalar multiplication (LSB double-and-add) + // ------------------------------------------------------------------------- + + public function scalarMul(\GMP $k): self + { + if (gmp_sign($k) === 0) { + return self::identity(); + } + + $result = self::identity(); + $addend = $this; + $n = gmp_abs($k); + + while (gmp_cmp($n, gmp_init(0)) > 0) { + if (gmp_testbit($n, 0)) { + $result = $result->add($addend); + } + $addend = $addend->double(); + $n = gmp_div($n, gmp_init(2)); + } + + if (gmp_sign($k) < 0) { + return $result->neg(); + } + + return $result; + } + + // ------------------------------------------------------------------------- + // Compressed serialization (ZCash encoding, 48 bytes) + // ------------------------------------------------------------------------- + + public function toCompressedBytes(): string + { + if ($this->isIdentity()) { + $bytes = str_repeat("\x00", 48); + $bytes[0] = chr(0xc0); // 0x80 (compressed) | 0x40 (infinity) + + return $bytes; + } + + // Convert to affine + $zinv = $this->z->inv(); + $zinv2 = $zinv->square(); + $zinv3 = $zinv2->mul($zinv); + $ax = $this->x->mul($zinv2); + $ay = $this->y->mul($zinv3); + + $bytes = $ax->toBytes(); // 48 bytes, top 3 bits of first byte are 0 + // Bit 7 (0x80): compressed flag + $bytes[0] = chr(ord($bytes[0]) | 0x80); + // Bit 5 (0x20): sort/sign flag, set if y > (p-1)/2 + if ($ay->isNegative()) { + $bytes[0] = chr(ord($bytes[0]) | 0x20); + } + + return $bytes; + } + + public function toHex(): string + { + return bin2hex($this->toCompressedBytes()); + } +} diff --git a/src/BLS/Curves/G2.php b/src/BLS/Curves/G2.php new file mode 100644 index 0000000..9cea68d --- /dev/null +++ b/src/BLS/Curves/G2.php @@ -0,0 +1,335 @@ +x = $x; + $this->y = $y; + $this->z = $z; + } + + public static function generator(): self + { + return new self( + Fp2::fromHex(self::GX_C0, self::GX_C1), + Fp2::fromHex(self::GY_C0, self::GY_C1), + Fp2::one() + ); + } + + public static function identity(): self + { + return new self(Fp2::zero(), Fp2::one(), Fp2::zero()); + } + + public function isIdentity(): bool + { + return $this->z->isZero(); + } + + // ------------------------------------------------------------------------- + // Point doubling (dbl-2009-l, a=0 for G2) + // ------------------------------------------------------------------------- + + public function double(): self + { + if ($this->isIdentity()) { + return self::identity(); + } + + $X = $this->x; + $Y = $this->y; + $Z = $this->z; + + $A = $X->square(); + $B = $Y->square(); + $C = $B->square(); + $D = $X->add($B)->square()->sub($A)->sub($C)->mulInt(2); + $E = $A->mulInt(3); + $F = $E->square(); + $X3 = $F->sub($D->mulInt(2)); + $Y3 = $E->mul($D->sub($X3))->sub($C->mulInt(8)); + $Z3 = $Y->mul($Z)->mulInt(2); + + return new self($X3, $Y3, $Z3); + } + + // ------------------------------------------------------------------------- + // Point addition + // ------------------------------------------------------------------------- + + public function add(self $other): self + { + if ($this->isIdentity()) { + return $other; + } + if ($other->isIdentity()) { + return $this; + } + + $X1 = $this->x; + $Y1 = $this->y; + $Z1 = $this->z; + $X2 = $other->x; + $Y2 = $other->y; + $Z2 = $other->z; + + $Z1Z1 = $Z1->square(); + $Z2Z2 = $Z2->square(); + $U1 = $X1->mul($Z2Z2); + $U2 = $X2->mul($Z1Z1); + $S1 = $Y1->mul($Z2)->mul($Z2Z2); + $S2 = $Y2->mul($Z1)->mul($Z1Z1); + $H = $U2->sub($U1); + $r = $S2->sub($S1)->mulInt(2); + + if ($H->isZero()) { + if ($r->isZero()) { + return $this->double(); + } + + return self::identity(); + } + + $I = $H->mulInt(2)->square(); + $J = $H->mul($I); + $V = $U1->mul($I); + $X3 = $r->square()->sub($J)->sub($V->mulInt(2)); + $Y3 = $r->mul($V->sub($X3))->sub($S1->mul($J)->mulInt(2)); + $Z3 = $Z1->add($Z2)->square()->sub($Z1Z1)->sub($Z2Z2)->mul($H); + + return new self($X3, $Y3, $Z3); + } + + public function neg(): self + { + return new self($this->x, $this->y->neg(), $this->z); + } + + // ------------------------------------------------------------------------- + // Scalar multiplication (LSB double-and-add) + // ------------------------------------------------------------------------- + + public function scalarMul(\GMP $k): self + { + if (gmp_sign($k) === 0) { + return self::identity(); + } + + $result = self::identity(); + $addend = $this; + $n = gmp_abs($k); + + while (gmp_cmp($n, gmp_init(0)) > 0) { + if (gmp_testbit($n, 0)) { + $result = $result->add($addend); + } + $addend = $addend->double(); + $n = gmp_div($n, gmp_init(2)); + } + + if (gmp_sign($k) < 0) { + return $result->neg(); + } + + return $result; + } + + /** + * ψ (psi) Frobenius endomorphism. + * ψ(x, y) = (conj(x) * PSI_X, conj(y) * PSI_Y) + * Applied to projective point (X:Y:Z): ψ(X:Y:Z) = (conj(X)*PSI_X : conj(Y)*PSI_Y : conj(Z)). + */ + public function psi(): self + { + if ($this->isIdentity()) { + return self::identity(); + } + $x2 = $this->x->conjugate()->mul(self::psiX()); + $y2 = $this->y->conjugate()->mul(self::psiY()); + $z2 = $this->z->conjugate(); + + return new self($x2, $y2, $z2); + } + + /** + * ψ² (psi squared) endomorphism. + * ψ²(x, y) = (x * PSI2_X, -y) + * In projective: (X*PSI2_X : -Y : Z) — no conjugation needed since PSI2_X ∈ Fp. + */ + public function psi2(): self + { + if ($this->isIdentity()) { + return self::identity(); + } + $x2 = $this->x->mul(self::psi2X()); + $y2 = $this->y->neg(); + + return new self($x2, $y2, $this->z); + } + + // ------------------------------------------------------------------------- + // Cofactor clearing via Bowe et al. efficient algorithm + // h_eff = (x² - x - 1)P + (x-1)ψ(P) + ψ²(2P) + // ------------------------------------------------------------------------- + + public function clearCofactor(): self + { + $x = gmp_init(self::BLS_X, 16); + + $t1 = $this->scalarMul($x)->neg(); // [-x]P + $t2 = $this->psi(); // ψ(P) + $t3 = $this->double(); // 2P + $t3 = $t3->psi2(); // ψ²(2P) + $t3 = $t3->sub($t2); // ψ²(2P) - ψ(P) + $t2 = $t1->add($t2); // [-x]P + ψ(P) + $t2 = $t2->scalarMul($x)->neg(); // -[x]([-x]P + ψ(P)) = [x²]P - [x]ψ(P) + $t3 = $t3->add($t2); // ψ²(2P) - ψ(P) + [x²]P - [x]ψ(P) + $t3 = $t3->sub($t1); // + [x]P (sub neg = add) + $Q = $t3->sub($this); // - P + + return $Q; + } + + // sub is just add(neg) + public function sub(self $other): self + { + return $this->add($other->neg()); + } + + // ------------------------------------------------------------------------- + // Convert to affine + // ------------------------------------------------------------------------- + + public function toAffine(): array // [Fp2 $x, Fp2 $y] + { + if ($this->isIdentity()) { + return [Fp2::zero(), Fp2::one()]; + } + $zinv = $this->z->inv(); + $zinv2 = $zinv->square(); + $zinv3 = $zinv2->mul($zinv); + + return [$this->x->mul($zinv2), $this->y->mul($zinv3)]; + } + + // ------------------------------------------------------------------------- + // Compressed serialization (ZCash encoding, 96 bytes) + // G2 x ∈ Fp2: encode as c1 || c0 (each 48 bytes), total 96 bytes + // ------------------------------------------------------------------------- + + public function toCompressedBytes(): string + { + if ($this->isIdentity()) { + $bytes = str_repeat("\x00", 96); + $bytes[0] = chr(0xc0); // 0x80 (compressed) | 0x40 (infinity) + + return $bytes; + } + + [$ax, $ay] = $this->toAffine(); + + // Fp2 serialization: c1 (high 48 bytes) then c0 (low 48 bytes) + $bytes = $ax->c1->toBytes().$ax->c0->toBytes(); // 96 bytes, top 3 bits of first byte are 0 + + // Bit 7 (0x80): compressed flag + $bytes[0] = chr(ord($bytes[0]) | 0x80); + + // Bit 5 (0x20): sort/sign flag — determined by y, not x + // ZCash: if y.c1 != 0 then sign = (y.c1 > (p-1)/2) else sign = (y.c0 > (p-1)/2) + $signFp = $ay->c1->isZero() ? $ay->c0 : $ay->c1; + if ($signFp->isNegative()) { + $bytes[0] = chr(ord($bytes[0]) | 0x20); + } + + return $bytes; + } + + /** + * Lazily compute and cache the three Frobenius constants. + * base = 1/(1+u) in Fp2 = ((p+1)/2, (p-1)/2) + * PSI_X = base^((p-1)/3) + * PSI_Y = base^((p-1)/2) + * PSI2_X = base^((p²-1)/3). + */ + private static function initPsiConstants(): void + { + if (self::$psiX !== null) { + return; + } + $p = Fp::prime(); + $inv2 = gmp_div(gmp_add($p, gmp_init(1)), gmp_init(2)); // (p+1)/2 = mod-inverse of 2 + $base = new Fp2(new Fp($inv2), new Fp(gmp_sub($p, $inv2))); + + $p1 = gmp_sub($p, gmp_init(1)); + self::$psiX = $base->pow(gmp_div($p1, gmp_init(3))); + self::$psiY = $base->pow(gmp_div($p1, gmp_init(2))); + + $p2 = gmp_mul($p, $p); + $p2m1 = gmp_sub($p2, gmp_init(1)); + self::$psi2X = $base->pow(gmp_div($p2m1, gmp_init(3))); + } + + private static function psiX(): Fp2 + { + self::initPsiConstants(); + + return self::$psiX; + } + + private static function psiY(): Fp2 + { + self::initPsiConstants(); + + return self::$psiY; + } + + private static function psi2X(): Fp2 + { + self::initPsiConstants(); + + return self::$psi2X; + } +} diff --git a/src/BLS/EIP2333.php b/src/BLS/EIP2333.php new file mode 100644 index 0000000..1ed8dad --- /dev/null +++ b/src/BLS/EIP2333.php @@ -0,0 +1,132 @@ + 0 + $this->value = $v; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + public static function fromHex(string $hex): self + { + return new self(gmp_init($hex, 16)); + } + + public static function fromInt(int $n): self + { + return new self(gmp_init($n)); + } + + public static function zero(): self + { + return new self(gmp_init(0)); + } + + public static function one(): self + { + return new self(gmp_init(1)); + } + + public static function prime(): GMP + { + if (self::$prime === null) { + self::$prime = gmp_init(self::P_HEX, 16); + } + + return self::$prime; + } + + public static function order(): GMP + { + if (self::$order === null) { + self::$order = gmp_init(self::R_HEX, 16); + } + + return self::$order; + } + + // ------------------------------------------------------------------------- + // Arithmetic + // ------------------------------------------------------------------------- + + public function add(self $other): self + { + return new self(gmp_add($this->value, $other->value)); + } + + public function sub(self $other): self + { + $r = gmp_sub($this->value, $other->value); + if (gmp_sign($r) < 0) { + $r = gmp_add($r, self::prime()); + } + + return new self($r); + } + + public function mul(self $other): self + { + return new self(gmp_mul($this->value, $other->value)); + } + + public function square(): self + { + return new self(gmp_pow($this->value, 2)); + } + + public function neg(): self + { + if (gmp_sign($this->value) === 0) { + return self::zero(); + } + + return new self(gmp_sub(self::prime(), $this->value)); + } + + public function inv(): self + { + $inv = gmp_invert($this->value, self::prime()); + if ($inv === false) { + throw new \RuntimeException('Fp: element has no inverse (is zero)'); + } + + return new self($inv); + } + + public function pow(GMP $exp): self + { + return new self(gmp_powm($this->value, $exp, self::prime())); + } + + // ------------------------------------------------------------------------- + // Predicates + // ------------------------------------------------------------------------- + + public function isZero(): bool + { + return gmp_sign($this->value) === 0; + } + + public function equals(self $other): bool + { + return gmp_cmp($this->value, $other->value) === 0; + } + + /** sgn0: returns true if value is odd (used for hash-to-curve SWU) */ + public function isOdd(): bool + { + return gmp_testbit($this->value, 0); + } + + /** True if value > (p-1)/2 (used for ZCash compressed point sign bit) */ + public function isNegative(): bool + { + // p is odd, so (p-1)/2 = p >> 1 in integer arithmetic + return gmp_cmp($this->value, gmp_div(self::prime(), 2)) > 0; + } + + // ------------------------------------------------------------------------- + // Serialization + // ------------------------------------------------------------------------- + + /** Returns 48-byte big-endian representation */ + public function toBytes(): string + { + $hex = str_pad(gmp_strval($this->value, 16), 96, '0', STR_PAD_LEFT); + + return hex2bin($hex); + } +} diff --git a/src/BLS/Fields/Fp2.php b/src/BLS/Fields/Fp2.php new file mode 100644 index 0000000..94f53bd --- /dev/null +++ b/src/BLS/Fields/Fp2.php @@ -0,0 +1,176 @@ +c0 = $c0; + $this->c1 = $c1; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + public static function fromInts(int $c0, int $c1): self + { + return new self(Fp::fromInt($c0), Fp::fromInt($c1)); + } + + public static function fromHex(string $c0hex, string $c1hex): self + { + return new self(Fp::fromHex($c0hex), Fp::fromHex($c1hex)); + } + + public static function zero(): self + { + return new self(Fp::zero(), Fp::zero()); + } + + public static function one(): self + { + return new self(Fp::one(), Fp::zero()); + } + + // ------------------------------------------------------------------------- + // Arithmetic + // ------------------------------------------------------------------------- + + public function add(self $other): self + { + return new self($this->c0->add($other->c0), $this->c1->add($other->c1)); + } + + public function sub(self $other): self + { + return new self($this->c0->sub($other->c0), $this->c1->sub($other->c1)); + } + + /** + * Karatsuba multiplication in Fp2. + * (a + b·u)(c + d·u) = (ac - bd) + (ad + bc)·u [since u²=-1]. + */ + public function mul(self $other): self + { + $ac = $this->c0->mul($other->c0); + $bd = $this->c1->mul($other->c1); + $c0 = $ac->sub($bd); + // (a+b)(c+d) - ac - bd = ad + bc + $c1 = $this->c0->add($this->c1)->mul($other->c0->add($other->c1))->sub($ac)->sub($bd); + + return new self($c0, $c1); + } + + public function mulInt(int $n): self + { + $s = Fp::fromInt($n); + + return new self($this->c0->mul($s), $this->c1->mul($s)); + } + + public function square(): self + { + // (a + b·u)² = (a²-b²) + 2ab·u + $a = $this->c0; + $b = $this->c1; + $c0 = $a->add($b)->mul($a->sub($b)); // (a+b)(a-b) = a²-b² + $c1 = $a->mul($b)->mul(Fp::fromInt(2)); + + return new self($c0, $c1); + } + + public function neg(): self + { + return new self($this->c0->neg(), $this->c1->neg()); + } + + /** Frobenius / conjugate: (a + b·u)* = a - b·u */ + public function conjugate(): self + { + return new self($this->c0, $this->c1->neg()); + } + + public function inv(): self + { + // 1/(a + b·u) = (a - b·u) / (a² + b²) + $norm = $this->c0->square()->add($this->c1->square()); // a² + b² + $invNorm = $norm->inv(); + + return new self($this->c0->mul($invNorm), $this->c1->neg()->mul($invNorm)); + } + + /** + * Exponentiation by a large GMP integer. + */ + public function pow(GMP $exp): self + { + $result = self::one(); + $base = $this; + $e = gmp_abs($exp); + while (gmp_cmp($e, gmp_init(0)) > 0) { + if (gmp_testbit($e, 0)) { + $result = $result->mul($base); + } + $base = $base->square(); + $e = gmp_div($e, gmp_init(2)); + } + + return $result; + } + + // ------------------------------------------------------------------------- + // Predicates + // ------------------------------------------------------------------------- + + public function isZero(): bool + { + return $this->c0->isZero() && $this->c1->isZero(); + } + + public function equals(self $other): bool + { + return $this->c0->equals($other->c0) && $this->c1->equals($other->c1); + } + + /** + * sgn0_m_eq_2 from RFC 9380: sign of Fp2 element. + * Returns c0's parity unless c0==0, then c1's parity. + */ + public function isOdd(): bool + { + if (! $this->c0->isZero()) { + return $this->c0->isOdd(); + } + + return $this->c1->isOdd(); + } + + public static function cmov(self $a, self $b, bool $condition): self + { + return $condition ? $b : $a; + } + + // ------------------------------------------------------------------------- + // Serialization (96 bytes: c1 first 48 bytes, c0 last 48 bytes) + // G2 compressed: 96 bytes per coordinate pair, two pairs = 192 bytes total + // ------------------------------------------------------------------------- + + public function toBytes(): string + { + return $this->c1->toBytes().$this->c0->toBytes(); + } +} diff --git a/src/BLS/HashToCurve/G2HashToCurve.php b/src/BLS/HashToCurve/G2HashToCurve.php new file mode 100644 index 0000000..9866d5b --- /dev/null +++ b/src/BLS/HashToCurve/G2HashToCurve.php @@ -0,0 +1,380 @@ +add($q1)->clearCofactor(); + } + + // ========================================================================= + // expand_message_xmd (RFC 9380 §5.3.1, SHA-256 variant) + // ========================================================================= + + private static function expandMessageXmd(string $msg, string $dst, int $lenInBytes): string + { + $ell = (int) ceil($lenInBytes / self::B_IN_BYTES); // = 8 for 256 bytes + $dstPrime = $dst.chr(strlen($dst)); + $zPad = str_repeat("\x00", self::R_IN_BYTES); + $libStr = chr(($lenInBytes >> 8) & 0xff).chr($lenInBytes & 0xff); + + $b0 = hash('sha256', $zPad.$msg.$libStr."\x00".$dstPrime, true); + $b = []; + $b[0] = hash('sha256', $b0."\x01".$dstPrime, true); + + for ($i = 1; $i < $ell; $i++) { + $b[$i] = hash('sha256', self::strxor($b0, $b[$i - 1]).chr($i + 1).$dstPrime, true); + } + + return substr(implode('', $b), 0, $lenInBytes); + } + + private static function strxor(string $a, string $b): string + { + $out = ''; + $len = strlen($a); + for ($i = 0; $i < $len; $i++) { + $out .= chr(ord($a[$i]) ^ ord($b[$i])); + } + + return $out; + } + + // ========================================================================= + // hash_to_field: 256 uniform bytes → two Fp2 elements + // Layout: [e0_c0 (64B), e0_c1 (64B), e1_c0 (64B), e1_c1 (64B)] + // ========================================================================= + + /** + * @return Fp2[] [u0, u1] + */ + private static function uniformBytesToFp2Pair(string $bytes, int $L): array + { + // m=2 extension, count=2 elements + // offset = L * (j + i * m) + // e0: j=0 → offset 0, j=1 → offset 64 + // e1: j=0 → offset 128, j=1 → offset 192 + $p = Fp::prime(); + $u0 = new Fp2( + new Fp(gmp_mod(gmp_init(bin2hex(substr($bytes, 0, $L)), 16), $p)), + new Fp(gmp_mod(gmp_init(bin2hex(substr($bytes, $L, $L)), 16), $p)) + ); + $u1 = new Fp2( + new Fp(gmp_mod(gmp_init(bin2hex(substr($bytes, 2 * $L, $L)), 16), $p)), + new Fp(gmp_mod(gmp_init(bin2hex(substr($bytes, 3 * $L, $L)), 16), $p)) + ); + + return [$u0, $u1]; + } + + // ========================================================================= + // SWU map: Fp2 element → affine point on isogenous E' + // Then apply the 3-isogeny to land on actual G2 curve E. + // ========================================================================= + + private static function mapToCurveG2(Fp2 $u): G2 + { + // SWU curve parameters + // A' = 240·u + $A = Fp2::fromInts(0, 240); + // B' = 1012 + 1012·u + $B = Fp2::fromInts(1012, 1012); + // Z = -(2 + u) = (p-2) + (p-1)·u + $p = Fp::prime(); + $Z = new Fp2(new Fp(gmp_sub($p, gmp_init(2))), new Fp(gmp_sub($p, gmp_init(1)))); + $F1 = Fp2::one(); + + // RFC 9380 §6.6.2 Simplified SWU, 25 steps (noble-curves numbering): + // prettier-ignore + $tv1 = $u->square(); // 1. tv1 = u² + $tv1 = $Z->mul($tv1); // 2. tv1 = Z * tv1 + $tv2 = $tv1->square(); // 3. tv2 = tv1² + $tv2 = $tv2->add($tv1); // 4. tv2 = tv2 + tv1 + $tv3 = $tv2->add($F1); // 5. tv3 = tv2 + 1 + $tv3 = $B->mul($tv3); // 6. tv3 = B * tv3 + // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + $tv4 = Fp2::cmov($Z, $tv2->neg(), ! $tv2->isZero()); + $tv4 = $A->mul($tv4); // 8. tv4 = A * tv4 + $tv2 = $tv3->square(); // 9. tv2 = tv3² + $tv6 = $tv4->square(); // 10. tv6 = tv4² + $tv5 = $A->mul($tv6); // 11. tv5 = A * tv6 + $tv2 = $tv2->add($tv5); // 12. tv2 = tv2 + tv5 + $tv2 = $tv2->mul($tv3); // 13. tv2 = tv2 * tv3 + $tv6 = $tv6->mul($tv4); // 14. tv6 = tv6 * tv4 + $tv5 = $B->mul($tv6); // 15. tv5 = B * tv6 + $tv2 = $tv2->add($tv5); // 16. tv2 = tv2 + tv5 + $x = $tv1->mul($tv3); // 17. x = tv1 * tv3 + + // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + ['isValid' => $isValid, 'value' => $y1] = self::sqrtRatio($tv2, $tv6); + + $y = $tv1->mul($u); // 19. y = tv1 * u (= Z·u³ * y_coeff) + $y = $y->mul($y1); // 20. y = y * y1 + + $x = Fp2::cmov($x, $tv3, $isValid); // 21. x = CMOV(x, tv3, is_gx1_square) + $y = Fp2::cmov($y, $y1, $isValid); // 22. y = CMOV(y, y1, is_gx1_square) + + // 23. e1 = (sgn0(u) == sgn0(y)) + $e1 = ($u->isOdd() === $y->isOdd()); + // 24. y = CMOV(-y, y, e1) + $y = Fp2::cmov($y->neg(), $y, $e1); + + // 25. x = x / tv4 + $x = $x->mul($tv4->inv()); + + // Apply 3-isogeny to get point on actual G2 curve + [$xi, $yi] = self::applyIsogeny($x, $y); + + // Return as Jacobian G2 point (Z=1) + return new G2($xi, $yi, Fp2::one()); + } + + // ========================================================================= + // RFC 9380 Appendix F.2.1.2 — sqrt_ratio for Fp2 (q ≡ 9 mod 16, c1=3) + // Returns { isValid, value } where value = sqrt(u/v) if QR, else sqrt(Z·u/v) + // ========================================================================= + + /** + * @return array{isValid: bool, value: Fp2} + */ + private static function sqrtRatio(Fp2 $u, Fp2 $v): array + { + [$c6, $c7] = self::swuPrecompute(); + + $c5 = gmp_init(4); // 2^(c1-1) = 4 + $c3 = self::swuC3(); + + // Steps 1-16 + $tv1 = $c6; // 1 + $tv2 = self::fp2Pow7($v); // 2. v^7 + $tv3 = $tv2->square()->mul($v); // 3-4. v^14 * v = v^15 + $tv5 = $u->mul($tv3); // 5. u * v^15 + $tv5 = $tv5->pow($c3); // 6. (u * v^15)^c3 + $tv5 = $tv5->mul($tv2); // 7. * v^7 + $tv2 = $tv5->mul($v); // 8. + $tv3 = $tv5->mul($u); // 9. + $tv4 = $tv3->mul($tv2); // 10. + $tv5 = $tv4->pow($c5); // 11. tv4^4 + $isQR = $tv5->equals(Fp2::one()); // 12. + $tv2 = $tv3->mul($c7); // 13. + $tv5 = $tv4->mul($tv1); // 14. tv4 * c6 + $tv3 = Fp2::cmov($tv2, $tv3, $isQR); // 15. + $tv4 = Fp2::cmov($tv5, $tv4, $isQR); // 16. + + // Steps 17-26: loop i = c1 downto 2 (i.e., i = 3 then i = 2) + for ($i = 3; $i >= 2; $i--) { + // tv5 = 2^(i-2): for i=3 → 2, for i=2 → 1 + $powExp = ($i === 3) ? 2 : 1; + $tvv5 = ($powExp === 2) ? $tv4->square() : $tv4; // tv4^powExp + $e1 = $tvv5->equals(Fp2::one()); // 21. + $tv2 = $tv3->mul($tv1); // 22. + $tv1 = $tv1->square(); // 23. + $tvv5 = $tv4->mul($tv1); // 24. + $tv3 = Fp2::cmov($tv2, $tv3, $e1); // 25. + $tv4 = Fp2::cmov($tvv5, $tv4, $e1); // 26. + } + + $isValid = ! $v->isZero() && ($isQR || $u->isZero()); + + return ['isValid' => $isValid, 'value' => $tv3]; + } + + /** Fp2^7 via binary method (3 squarings + 3 muls) */ + private static function fp2Pow7(Fp2 $v): Fp2 + { + $v2 = $v->square(); // v² + $v4 = $v2->square(); // v⁴ + + return $v4->mul($v2)->mul($v); // v⁶ * v = v⁷ + } + + // ========================================================================= + // Precomputation of sqrtRatio constants c6 and c7 (lazily cached) + // c1 = 3, q = p², c2 = (q-1)/8, c3 = (c2-1)/2 + // c6 = Z^c2, c7 = Z^((c2+1)/2) + // ========================================================================= + + /** @return Fp2[] [c6, c7] */ + private static function swuPrecompute(): array + { + if (self::$swuC6 !== null) { + return [self::$swuC6, self::$swuC7]; + } + + $p = Fp::prime(); + $q = gmp_mul($p, $p); // q = p² + $q1 = gmp_sub($q, gmp_init(1)); // q - 1 + $c2 = gmp_div($q1, gmp_init(8)); // (q-1) / 8 + + // Z = -(2 + u) = (p-2) + (p-1)·u + $Z = new Fp2(new Fp(gmp_sub($p, gmp_init(2))), new Fp(gmp_sub($p, gmp_init(1)))); + + self::$swuC6 = $Z->pow($c2); + self::$swuC7 = $Z->pow(gmp_div(gmp_add($c2, gmp_init(1)), gmp_init(2))); + + return [self::$swuC6, self::$swuC7]; + } + + private static function swuC3(): \GMP + { + static $c3 = null; + if ($c3 === null) { + $p = Fp::prime(); + $q = gmp_mul($p, $p); + $c2 = gmp_div(gmp_sub($q, gmp_init(1)), gmp_init(8)); + $c3 = gmp_div(gmp_sub($c2, gmp_init(1)), gmp_init(2)); + } + + return $c3; + } + + // ========================================================================= + // 3-isogeny: E' → G2 curve E (rational map via Horner evaluation) + // ========================================================================= + + /** @return Fp2[] [x, y] */ + private static function applyIsogeny(Fp2 $x, Fp2 $y): array + { + $xn = self::horner(self::ISO_XN, $x); + $xd = self::horner(self::ISO_XD, $x); + $yn = self::horner(self::ISO_YN, $x); + $yd = self::horner(self::ISO_YD, $x); + + $xi = $xn->mul($xd->inv()); + $yi = $y->mul($yn->mul($yd->inv())); + + return [$xi, $yi]; + } + + /** + * Horner evaluation of a polynomial at x. + * Coefficients in ascending order [k0, k1, ..., kd] are reversed for Horner. + * Result: k0 + k1*x + ... + kd*x^d = horner([kd,...,k1,k0], x). + */ + private static function horner(array $ascCoeffs, Fp2 $x): Fp2 + { + $coeffs = array_reverse( + array_map(function ($pair) { + // '0' is falsy in PHP so use explicit comparison + $c0 = ($pair[0] !== '' && $pair[0] !== null) ? $pair[0] : '0'; + $c1 = ($pair[1] !== '' && $pair[1] !== null) ? $pair[1] : '0'; + + return Fp2::fromHex($c0, $c1); + }, $ascCoeffs) + ); + $acc = $coeffs[0]; + for ($i = 1, $n = count($coeffs); $i < $n; $i++) { + $acc = $acc->mul($x)->add($coeffs[$i]); + } + + return $acc; + } +} diff --git a/src/BLS/ProofOfPossession.php b/src/BLS/ProofOfPossession.php new file mode 100644 index 0000000..2602315 --- /dev/null +++ b/src/BLS/ProofOfPossession.php @@ -0,0 +1,96 @@ +scalarMul($scalar)->toHex(); + } + + /** + * Builds the Proof of Possession for a given private key. + * + * PoP = Sign(sk, Hash_G2(pk)) where Hash_G2 hashes the G1 public key bytes + * to a G2 point under POP_DST, then the G2 point is "signed" by multiplying + * by the private key scalar. + * + * @param string $privateKeyBytes 32-byte raw private key + * @throws InvalidArgumentException if the key is not exactly 32 bytes or is the zero scalar + * @return array{pk: string, pop: string} hex-encoded G1 pk (96 chars) and G2 pop (192 chars) + */ + public static function buildProofOfPossession(string $privateKeyBytes): array + { + if (strlen($privateKeyBytes) !== 32) { + throw new InvalidArgumentException( + 'BLS secret key must be exactly 32 bytes, got '.strlen($privateKeyBytes) + ); + } + + $sk = gmp_init(bin2hex($privateKeyBytes), 16); + + if (gmp_sign($sk) === 0) { + throw new InvalidArgumentException('BLS secret key must not be zero'); + } + + // G1 public key: [sk] * G1 + $pk = G1::generator()->scalarMul($sk)->toCompressedBytes(); + + // Hash pk bytes to G2 under POP_DST + $messagePoint = G2HashToCurve::hashToG2($pk, self::POP_DST); + + // Sign: PoP = [sk] * hash(pk) + $pop = $messagePoint->scalarMul($sk)->toCompressedBytes(); + + return [ + 'pk' => bin2hex($pk), + 'pop' => bin2hex($pop), + ]; + } + + /** + * Convenience: derive private key from mnemonic and build PoP. + * + * @return array{pk: string, pop: string} + */ + public static function fromMnemonic(string $mnemonic): array + { + return self::buildProofOfPossession(self::deriveBlsPrivateKey($mnemonic)); + } +} diff --git a/tests/Unit/BLS/EIP2333Test.php b/tests/Unit/BLS/EIP2333Test.php new file mode 100644 index 0000000..0dd8ffc --- /dev/null +++ b/tests/Unit/BLS/EIP2333Test.php @@ -0,0 +1,19 @@ +toBe(EIP2333_EXPECTED_SK); +}); + +it('produces different private keys for different mnemonics', function () { + $a = EIP2333::deriveBlsPrivateKey(EIP2333_MNEMONIC); + $b = EIP2333::deriveBlsPrivateKey('zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong'); + expect(bin2hex($a))->not->toBe(bin2hex($b)); +}); diff --git a/tests/Unit/BLS/ProofOfPossessionTest.php b/tests/Unit/BLS/ProofOfPossessionTest.php new file mode 100644 index 0000000..7bcefd3 --- /dev/null +++ b/tests/Unit/BLS/ProofOfPossessionTest.php @@ -0,0 +1,102 @@ +toBe(96) + ->and(strlen($result['pop']))->toBe(192); +}); + +it('is deterministic for the same secret key', function () { + $a = ProofOfPossession::buildProofOfPossession(hex2bin(POP_SK_A_HEX)); + $b = ProofOfPossession::buildProofOfPossession(hex2bin(POP_SK_A_HEX)); + expect($a['pk'])->toBe($b['pk']) + ->and($a['pop'])->toBe($b['pop']); +}); + +it('produces different pk and pop for different secret keys', function () { + $a = ProofOfPossession::buildProofOfPossession(hex2bin(POP_SK_A_HEX)); + $b = ProofOfPossession::buildProofOfPossession(hex2bin(POP_SK_B_HEX)); + expect($a['pk'])->not->toBe($b['pk']) + ->and($a['pop'])->not->toBe($b['pop']); +}); + +it('pk matches deriveBlsPublicKey for the same secret key', function () { + $result = ProofOfPossession::buildProofOfPossession(hex2bin(POP_SK_A_HEX)); + $expected = ProofOfPossession::privateKeyToPublicKey(hex2bin(POP_SK_A_HEX)); + expect($result['pk'])->toBe($expected); +}); + +it('matches the pinned test vector for SK_A', function () { + $result = ProofOfPossession::buildProofOfPossession(hex2bin(POP_SK_A_HEX)); + expect($result['pk'])->toBe(EXPECTED_PK_A) + ->and($result['pop'])->toBe(EXPECTED_POP_A); +}); + +it('throws on a secret key of wrong length', function () { + expect(fn () => ProofOfPossession::buildProofOfPossession(str_repeat("\x00", 31)))->toThrow(InvalidArgumentException::class) + ->and(fn () => ProofOfPossession::buildProofOfPossession(str_repeat("\x00", 33)))->toThrow(InvalidArgumentException::class) + ->and(fn () => ProofOfPossession::buildProofOfPossession(''))->toThrow(InvalidArgumentException::class); +}); + +it('throws on the zero secret key', function () { + expect(fn () => ProofOfPossession::buildProofOfPossession(str_repeat("\x00", 32)))->toThrow(InvalidArgumentException::class); +}); + +// ------------------------------------------------------------------------- +// deriveBlsPublicKey +// ------------------------------------------------------------------------- + +it('returns a 96-character hex string (48-byte G1)', function () { + $pk = ProofOfPossession::deriveBlsPublicKey(POP_PASSPHRASE); + expect(strlen($pk))->toBe(96); +}); + +it('is deterministic for the same passphrase', function () { + $pk = ProofOfPossession::deriveBlsPublicKey(POP_PASSPHRASE); + expect($pk)->toBe(EXPECTED_MNEMONIC_PK); +}); + +it('matches the pinned pop for the same passphrase', function () { + $result = ProofOfPossession::fromMnemonic(POP_PASSPHRASE); + expect($result['pk'])->toBe(EXPECTED_MNEMONIC_PK) + ->and($result['pop'])->toBe(EXPECTED_MNEMONIC_POP); +}); + +// ------------------------------------------------------------------------- +// Table-driven derivation vectors +// Each entry: [mnemonic, private key (hex), public key (hex), proof of possession (hex)] +// ------------------------------------------------------------------------- + +$blsDataset = []; +foreach (json_decode(file_get_contents(__DIR__.'/../../fixtures/bls-keys.json'), true) as $lang => $vectors) { + foreach ($vectors as $i => $vector) { + $blsDataset["{$lang} #{$i}"] = array_values($vector); + } +} + +it('derives correct public key, private key, and pop for the given mnemonic', function (string $mnemonic, string $expectedSk, string $expectedPk, string $expectedPop) { + expect(bin2hex(EIP2333::deriveBlsPrivateKey($mnemonic)))->toBe($expectedSk); + + $result = ProofOfPossession::fromMnemonic($mnemonic); + expect($result['pk'])->toBe(substr($expectedPk, 2)) + ->and($result['pop'])->toBe(substr($expectedPop, 2)); +})->with($blsDataset); diff --git a/tests/fixtures/bls-keys.json b/tests/fixtures/bls-keys.json new file mode 100644 index 0000000..7c97867 --- /dev/null +++ b/tests/fixtures/bls-keys.json @@ -0,0 +1,322 @@ +{ + "czech": [ + { + "mnemonic": "najisto kazivost vpravo namluvit exkurze lord hladovka svoboda obejmout ukazatel pustina srpen metr ohrozit autobus pobyt omeleta bledule cizost petrolej nikl celkem jelen poezie", + "validatorPrivateKey": "6521a909bed1652044b99809b0a3c6999a9bd3a9c760e27e30fbda5931fa76a5", + "validatorPublicKey": "0x86e47e024116003fcf4a6b9150de36964d6590eb11b0f4a1607b89e11d99a4f8609e234eb8185ecf2c77edade1c95309", + "validatorPop": "0xae1f97166e6e444101184825116f03d1607d4387fcd3c0bc71c4a3d125858a8f236d948cab97c6bc1f9f8b6c487ed8f31439ec47e16321e090989bd20b9a4bab069a807935b2c141c221a04422a8ebe2fe84da839fc10dd665db170e24692069" + }, + { + "mnemonic": "louskat seshora hledat zahrada buvol vyrazit opravdu munice strom vyhledat barva vyrazit prorok lord manko hojnost zmizet dovozce lidojed bojovat nikdy hodiny spousta manko", + "validatorPrivateKey": "43aafbb031406eec46f79604a5615806c0880e0d8b2d6e722f03d7eba86db4e6", + "validatorPublicKey": "0x875032037e45a884e58629825c57d9e381e45ed0df3250b324aaf767fbc5a47a69a06a89af8998ed90a5c061e4cfbe20", + "validatorPop": "0xb4d356027006865734b10e05d4b943f3cde3628ca9763f719434a8d99e6f3ce5fae367c9806bfb7e9cdd5784f1b89afc160828fa4ff74ad0496453b7a83dfebf657ac016e601454146458c88fb7b4a5f123d18677f4200cdfa83eb63eee9100a" + }, + { + "mnemonic": "pastelka makak panna boubel pazourek zimnice louka prodej videohra chrlit referent smrk bulva varan smilstvo spis vztah potvora postava astma vystavit rampouch odpor duha", + "validatorPrivateKey": "3f941bba361aa5273e560cd4de20e747586e430efcb27fe14556f442808a477b", + "validatorPublicKey": "0x9684cc2ca48aca7f5827d1bdc33c1e6c8986c390309855221be1a74695986f9d7a9f8fa56e86027ab3e332b6f2a7a34e", + "validatorPop": "0x84b871933fe3a610000e581aa3d77c4d168ebc64691cf7ac702541b4eab54b5d0ac790c73e7675e52535274734a5e71b11f2bb16dcc8d366575450bedef56e32e1d4cf584f2795cdb2d4ea773a8931db739905ef91c5bb9db85a63848d3a23cf" + }, + { + "mnemonic": "dort okno zajatec tykev komando mlha lucifer astma malina puklina tendence starosta bacil baret mobil odjet propad zjemnit obava petrolej mezera baculka piha hadr", + "validatorPrivateKey": "3f09d1651e7a6d1d5f869db241fc94e578b1f3926977985ac96206225e047a3a", + "validatorPublicKey": "0xa774065223115fda52052087df0e792a17ba5ae3a1dddddafcd06c347f5905ac9dba5873e24df920c772d9ebe6a1548c", + "validatorPop": "0x8dda28ddf6c5589afc42c6cd3cf497e4f6da95343fafb1278154350338528cc624a3389bcc612bc7ecdc6a7fb2c6f4d511a3904170e4ca9fc371949fdbdbec3186dde06fc18644ba41c758a79f3aa4a55c544f550d56799d5f37434a71f21b4b" + }, + { + "mnemonic": "levitace truhlice otop ledvina buchta hala madlo jinoch doplnit baterka podzim dareba sluha cejn objasnit zastavit meditace mezera ulovit osten znalost exkurze plivat lucifer", + "validatorPrivateKey": "48bf069ca2917eeeee612e6fd50a1f6fb2c28af9167ee04cdd03c21240336d6d", + "validatorPublicKey": "0x858055545004fc6ef228bb4f23e2db530949d606f5e91620752a92d330dd59ef455bcb4214a64817adeb543aa2ea1287", + "validatorPop": "0xa79748c76577bf84f7ad4003c432bf69896cebcce9da6ba1802025d037b2622db015ba297d34b9677255baafe29b31560acb47d606105a8245c71dbcaefe1bcec10c75995b293d86c1ec72b2dd552ef153e8da890a952908ba0a14628cfdce88" + } + ], + "chinese_simplified": [ + { + "mnemonic": "法 何 又 莫 策 崇 须 裁 牲 者 阳 内 勇 逻 业 规 爆 院 葡 的 疑 传 面 运", + "validatorPrivateKey": "3f8e1457866e218d380add85494fddd6ae348e5cdae18b41394921e33baaad71", + "validatorPublicKey": "0xa5d586adc473d892ba361823b4a37380da77d1b9e4f44af76550a19270b88fefd4cf6bc1fefeb6d57b65b0d979facc0d", + "validatorPop": "0xb87264f324798a225770fc5a25189edaec7e048d686c068051717da80b7b4f35816473ef122612b090b473087f0d1d320208561ed58c2b2b421404fa4e1da101effbe174e3de1faaa780bac43c8c7919d806bcae56daf4022a221c05b1b24949" + }, + { + "mnemonic": "脚 哩 衡 片 阁 窗 众 辽 预 韩 普 腐 辅 惨 无 日 氨 罐 方 羊 齐 准 尚 纹", + "validatorPrivateKey": "024404c9af88605fbb2ec501d1406a55e087d57d4d0f92e9292ebd88183a472e", + "validatorPublicKey": "0x8ba06b7f5a72a2a11f6b314e3575b4924838e613cccc5d9583c92a9707d19ada047ca241e4307655be7e22669ac95c56", + "validatorPop": "0x8d32cbb32984ec2a67f16bbd4a6059052c6bd68a1a1541ee06427dc01544f5916c8799984c408f5e52661b31e3c79c910eec0d580a00ba87b1ca1028ea2c59b5396a867ec18d9dd8e0d06d925019e4376fb78f57c124869085f22eb224f3846b" + }, + { + "mnemonic": "萄 丝 鲁 剥 稍 礼 妥 湘 役 曲 洲 欲 岗 端 速 邓 逻 团 又 磁 内 烦 寿 闲", + "validatorPrivateKey": "35219fbe53eda1b8745d7c59464f3d3c43f47d0bb48d2343bea4cd76b782ab51", + "validatorPublicKey": "0x936ce7f333977bcb0895374a5f286832575be4f57a4a624614024cc5167d3b7eee4844b9eb927cdd0d0d89aa30e27837", + "validatorPop": "0xa95043477e03abac2e23aa360b2bda57f3d32f1ea7fbcb62be5e0a6d1a504731be10a07449d08452110c553de4d5746510afdebf224955537a65d39f0dbf203303b9786c122c9c246e07a8e11f1df881819bb79990c0af8f60f22c5974dcfc2b" + }, + { + "mnemonic": "谋 死 只 版 韩 睡 释 逐 凤 知 春 氯 足 滩 蜡 整 叹 丰 沙 游 填 核 屋 砂", + "validatorPrivateKey": "133c8941693353846ddacdc1bf25a2425797ae75cf05a5cc641df97cf09e0ce3", + "validatorPublicKey": "0x8bf91fdd97b7e318ffa40a9554eef55101c2af60ce3e9a82cc0a5a5349b73b45293fd8fb4c5c1b038230bfd8eda17af6", + "validatorPop": "0xb3660b201bcb7c631b08beeef26ab9c5150528446a9bca206b31a5d0ad5a62c0321cbd4fb140624312ebc1785df7bd2616875e2ba1e285b6129420aa0ce4459dd74b6bee51e8f8f048736a407b006256d23e1371b81c66566ddfd8ba6bb5bed8" + }, + { + "mnemonic": "颜 郎 情 冬 煤 既 库 绝 汁 元 泽 涉 嘛 票 风 筛 隆 突 滴 神 临 壮 爷 晶", + "validatorPrivateKey": "1c7e0331a7d2a695a1603a85ed2844a9270a53001f4095d30295f612cd2c2628", + "validatorPublicKey": "0xa497a5851a04f16167587807a3f2e9ea4764ecda9b434e041b4c1086466370e99f88754c429359b5e8f3f9fcf3727e86", + "validatorPop": "0x8874968b524621ccc090d595481eae97b9e5ec2404d4fa50466565c27d8b9b130ec38c12881898c1713bcf93a1ea50740378c70bacf49fdfadcd9172a0ccc4256baa2a9fc12b37c9330a2fa5c283f59f4860f726244bc2749db32e81273e3966" + } + ], + "chinese_traditional": [ + { + "mnemonic": "銷 鑽 隔 責 雅 丁 來 旋 爐 轉 害 睡 狂 太 善 馮 集 籌 蓮 爐 懸 生 試 盜", + "validatorPrivateKey": "0602d2cfb5a77b14aa98a996242583148f14ee8043b50cf8cece083a81cc0221", + "validatorPublicKey": "0x96cec279ae8aaad8d78f7367532b864d17b129bf3e9019a5581427f10812f32911eb3e3c795eb4bfcfd58d85b6dabdbd", + "validatorPop": "0xa08fc77623fe2aa660cb6f16a6c211313bb85ac9a355af579fd9e252cfa26abddf7d112d823a0aded9916a2bf38db83e1752d34f6fb653e8847a3ddd8b075dcb864eb88d09e0c429c35157501672d15ec5dc274fdd2ff6da216d28f271a11bc2" + }, + { + "mnemonic": "序 付 撞 盆 憶 汗 幕 懲 會 氏 殿 忍 皺 累 躺 酯 全 陸 起 拜 芳 闊 舊 耐", + "validatorPrivateKey": "55458f5510a4eaa27c354efb5e02d24e153af112e19c94c43d559f717cd7f617", + "validatorPublicKey": "0xb2ec5958b2ac4f7762e5c131187d39dddbcbeecc3d42cf29778eddf2073d3858e88ae74360973a869d8e3856708bc7b5", + "validatorPop": "0xa1bc5c22ee93bc49a60421faa3d81395005f94fb9cb42156aea21c2cb5eac2f12c39356565600cd559ed9e96d37dcad202eb93d1067a8cb08bd98868f4ed236805c2560a4bd7496ce2d5c2696f175e0cd1a1cd70b617ecf47b55cdfa161e8cab" + }, + { + "mnemonic": "很 造 衰 姿 整 慘 扇 代 糞 器 蘭 沒 其 啟 半 取 界 績 拍 太 慶 利 調 巧", + "validatorPrivateKey": "5c699b7e942eb59dc13fb39a4d704087de03daf9018b6b321f3818a668a8a3a7", + "validatorPublicKey": "0xa81d874c17a6ee136782c009414a06bfa2465943b30f450fd0a40e287fbc25617f28a5c5cf02b7b0e847aff8fe32edbf", + "validatorPop": "0x92e9fcc48841568ec6501093f88af0964cb0f716d90ce60c748ba4ecc2568cd091ce6fa640ebef0c97c81db9320586ab126681e58921eab1fff2688ff81e5bd51ef199892199e03a424fa1a842920ac161a01276702c2535675c080563c005f3" + }, + { + "mnemonic": "砂 宗 哪 鬧 忙 討 播 胺 赤 朋 底 訪 僚 新 握 卵 曰 察 訂 尖 輯 恆 止 忘", + "validatorPrivateKey": "12d39f9a39757c7dd5be3bad73e3471962f548633de68df90f6d01a111670425", + "validatorPublicKey": "0x885a2e7c0bcac2c36ab54808056bb5ba924c35313d5363eb05af7f1fefb412bae5c905cf45522f3cb3fdf96a88e748a7", + "validatorPop": "0xab5d6fb58af1411574c34421a5bb99ac7811e8d2d7d35751ce531a92aabf020094e4beb322bf366914d615386d0cb542137472076cb1dbb85f6f3ca1157f11e19be6ae1a7d7b0097d627015bd94b0d3129b79697f0ae2179a5e16ddd8cad620c" + }, + { + "mnemonic": "少 割 宋 誰 潮 爺 稱 報 訊 遺 協 專 騰 恨 手 賴 誣 裂 素 洗 節 線 霍 含", + "validatorPrivateKey": "25624f9a90c7d545ba7a69fc74c82ea598ea4cb60b877814468d74b3efd10aff", + "validatorPublicKey": "0x8da1045c92f7bc2379017b20520fb9608f2c91de52c7727a3b1b7e882ee6859dcc113a645fcaf21b3f4d2f705edae7a5", + "validatorPop": "0x97768e349b4f81ddc46c569d83f0d8c549a19c171d8a25c5850fc5181e5801df39dbf547f81b6a23605ef1d43146568c0dc4ed7752b20ac551763ec0eee7765fff727f21acd4a2fd63e3270ff2f29fa651289343645511425bde1e5048cd3614" + } + ], + "korean": [ + { + "mnemonic": "국왕 연설 혜택 호랑이 막걸리 이월 손길 말기 민주 해안 먹이 특징 여섯 가끔 증상 먹이 곡식 산책 본래 회전 잠자리 오염 매번 행동", + "validatorPrivateKey": "6f216814b1b9fcfe5b8185d5b517653e15e4d5ee754deaf4bff7b211063550d6", + "validatorPublicKey": "0xaeee5e065035c25b6266592bfc229178bdcb191deda7181127c9d29627c66a9b7fa3719e38baaefc0f531a053e70d206", + "validatorPop": "0x81ff1c7b3bb928a0b15122dd07b1399baf41609a00c323e55d72a67db9805ddea637b4bd6bfaf2184f532bdead2e7cdd0888d3b964473945adade0c9816701c699980755e42c313d834beccec56ee4c2e15427af92a9a4d1bb231d7273e0caa7" + }, + { + "mnemonic": "소용 수염 대도시 매일 실시 강조 살짝 청년 시청 문화 열정 호남 염려 학기 감소 본질 선풍기 인연 고전 모퉁이 직장 심사 무척 약간", + "validatorPrivateKey": "3ca9d88bfb7ab349245fe2bb84c5afd4432644cfdae91721c971c7d5e527e1f4", + "validatorPublicKey": "0xa6ec74718fe6a26e9f2a9b2796afd35a1166a4af0d1abaab16934e15132ef470e30d2934d1bf5f7f5aca1310bdab9301", + "validatorPop": "0x8e11d01913d4eaee2e1b12b23a8cbb9acf77bf524c17fc4d65e7c97fb132e7757292bf0b8fadf9eae3ce381659f407d004766389f8e0a38f4c14fc0133983a9d98e4e2b6420bd3e30f7c1134c0a84ac86953297ebcb1c9db48ea113b4e76bc16" + }, + { + "mnemonic": "스튜디오 감자 막상 튀김 자율 횟수 선풍기 약수 볶음 현대 손질 카메라 패션 살인 합격 이틀 여인 국수 국제 광경 수면 법률 성함 대출", + "validatorPrivateKey": "0813cdaac3b3caf757b9042b2d1a41c9056230319a104884f7380e1a31edeec8", + "validatorPublicKey": "0xa83902896fb8d0537a0f5336fbd458085724ce7c6cdb01eb4c12c937922ed8769a2064492075f834f96274d2b27dac90", + "validatorPop": "0xb2e530a339c934fc3825145b24df71870f1d1c6e5a4df3bace09001034f1691f8e8186bd6cbe49aaeb1f26a802e6304d124d4f2aa4bc0bc356ec4cd9a851c80e1470f743ce241d4b56908cc9421f15ca676f338308a4ad54f56ef4146a27a81c" + }, + { + "mnemonic": "민간 장기간 반발 김밥 구속 도대체 부인 흥미 목표 특별 예선 방문 모양 팝송 시장 체력 국내 바람 한때 실천 채점 답변 서점 설탕", + "validatorPrivateKey": "4713625e63a40c9d8be9bf5fd1435fea867b8cd2d7d613f510327a5549b4e176", + "validatorPublicKey": "0x8d27677ece4df09c45b9d691ca3a48cfa911ddc57b2c65ad4a66497ba4cea2b0b3a47f93d81b44580e58c50bf5b04727", + "validatorPop": "0xa154a481d6d6a55a91dd3907503a69d31a30af91fdf7a3592eb9123740ed788dfb9e580d1d3219970b2b7412332af72202f8042a2ae4aaa408c733612299e9cd95ede7590948e96ccb698d39ae03b0e433a14a023cb912d290d1339a368e6ce3" + }, + { + "mnemonic": "빨간색 회전 서비스 악수 역사 기독교 주장 예절 승객 간접 청소 횟수 게시판 점차 잠자리 늑대 변동 전기 눈썹 성인 정성 예정 하룻밤 장인", + "validatorPrivateKey": "10f0db181425ee01de0a3df528464ac7182f11754eb7737611c2892ee695b80b", + "validatorPublicKey": "0x8f06ed86dc6361843cf2ebbf47571e145452e64f41967d43822cf8cab109e665d5183c3c508d9d88893d475113d3e2b8", + "validatorPop": "0x96c2f4684047651ae40f26a436ef676502d85929c3cdee8d4e6619204db7f3a977acacbb5f4bc18e93c5e108ade4a317070c98b78789b092d985f91c4cc569a727338a0764d6078b11d00c4b17ac93a196dc770ad0690403a036629e45e943b3" + } + ], + "french": [ + { + "mnemonic": "symbole calepin gicler brioche rouge cabanon carbone hurler serein butoir opportun cocasse défrayer cirer butoir frivole bagage néfaste rejeter galaxie vexer aliéner donateur menacer", + "validatorPrivateKey": "107192d3dc98087153d457970bc9a4d4699e103767134574d4af7dade62814ff", + "validatorPublicKey": "0x8d1c3cfe91046e6b94da25ac219452c0f9abaccf281e355d4ee761c28c8cc87f8de376b151d291bddb8f98801af9b271", + "validatorPop": "0xb7f306dc033e2a329a62dd84fc753e73ad1e05a5a485a14d7e389eb93c8ebcf0fbe085c3816f416c130384e35e7cdd430c51d6e48bc32a24bf20761856557dbb58844e01978fc8693574905f37da3aade681f33c28d6a2a41a4aa9f236f6a403" + }, + { + "mnemonic": "grimper effigie divertir draper cabanon chapitre prudence nuire branche émission sénateur atome cumuler perte élaborer ajuster chien gardien déborder héron belote essence affiche frégate", + "validatorPrivateKey": "62c55a8f78e0a1361135d2796153edb4c492c0a64f337d5ed9940caa139cfdec", + "validatorPublicKey": "0x89e0159d10ac7d9b8a1b44363cc22af0a8686e7259b5404a0990b49fd6f14870293dc00612dabc4fbc664c36b2e09d37", + "validatorPop": "0x96b2f03b164e2ef2c785d421e5be35af588f2239fac3e09e026f655666f4d9bfcf5bb7e82a347869e14076f606683faf178b32e654c51ce96a15a8fab3c0a23af3dd00783a3b7f5c80915e4aab0e7baaad34ee49b14eb70a06037723c6c42869" + }, + { + "mnemonic": "toboggan atelier photon allouer prologue usage dosage onctueux stipuler grogner culminer rivière période horrible simple digne chute désert curseur hérisson abrasif nocturne employer facette", + "validatorPrivateKey": "63beff3c9b144e4657b0a8c7e06bcb8dbdb6129f87b1bf7e9b088e086f753c72", + "validatorPublicKey": "0x815eb470bdf93279f329b2c6cb9cc562bb48a5e00b9feafdd1d20dc50a3b5c2d2b58c5fc2b988fc119fb58e8b41a38ea", + "validatorPop": "0xa1ccd9e855b5ef39bb0e69bdf05f4f01aea431e490fc5647469db76554433d368b0b09991d4ee522d48712a6442b939d0b5162422512cd2933738b90cf64e2d9902ed928c339f14809568671dcedb7e083e0ee01a6d52112eb1916c8d1129e45" + }, + { + "mnemonic": "malice rentrer étoffer fluctuer broder solitude infusion éjecter chocolat jupon bolide opprimer peser éduquer sottise muraille ultrason épilogue relief scélérat épuisant trésor loyal avril", + "validatorPrivateKey": "508d83d6facf5c975c026eaf935e6752bf8e4bad2c27060a347b21f40c995211", + "validatorPublicKey": "0x983fc5e5b106fbc4e1743b5fc2bcfe1c0a480606332c8f2399c4b7836ef7bb48d52cf966a1ed8188c33ff337cf0fc298", + "validatorPop": "0xa3ef835b102095d71526d8b389fbdb21382acb4a3699eda3c3c45fab373c8692c71c666581f4149002dc8a1e89055409077d4d26573f4a8db803f654260b263fa4a8b113bba3876572e8853be6ba6b10c5b825d106fa3c8ddec8019f414166a7" + }, + { + "mnemonic": "puzzle article fourmi groupe silicium voile amovible instinct tablier baril lessive lugubre grutier peigne respect public riposter sucre samedi dresser bilan censurer badge fiole", + "validatorPrivateKey": "68901c71a048ad1e0a6e173d99431209765274ccb44a424cf2b37812bcb8cb32", + "validatorPublicKey": "0xb6d31016d62701a79dd96355f170ac4ead35fe69d5c495fe66a51cd3ba6614701e1bb20dc4b66342bf0cac0cf962ccb3", + "validatorPop": "0x95f191017d80db3594edf7f89ecd5cb14df38315a5cdadebd26972472a82ed51ec61f2f298b9b67f2ec8aec8a780bd52075570349306257db974f548768f74a4fb68852b5b014418bb6ddb88abd4516bdc733ed3e20d9902ad38df817604b5fd" + } + ], + "italian": [ + { + "mnemonic": "assaggio deciso esito muscolo usanza fetta velina umorismo pratica dote arsenico volpe gasdotto delirio risibile scelto vapore verticale ricordo principe ausilio frana superbo vivido", + "validatorPrivateKey": "3d2cc5cffcf54dde9103d4d27484a8a1f2bcf3e6e2f46ac6f17abda8c14034e0", + "validatorPublicKey": "0x89f7c0f46c2c4d773bdb3af22d5395536cb5cd206ed54f5ed4568372c61e30f831999eb07ae2ac302ed67609af5093b9", + "validatorPop": "0x8e4b9a844a6ad22a4fd0ca3bcf5a420a647fc23b7415479be677eaee123f7f3e882fc51460c4fba20bb0f4aae3dd12f9163c360e5cea304cf209bd9ba850f0af6718cf77703d8a28a9c30e3153fa0a183254c09f3490ae6bdc9b3bdac23dc50b" + }, + { + "mnemonic": "addebito cellulare rassegna ferro selettivo sciroppo pineta sonda sfruttato nessuno veduto proposta pesatore daniela tariffa tizzone modello doblone cosmico rappreso pretesto ambito dentro frugale", + "validatorPrivateKey": "38a2c784846063065c35d4b20fbb58e0c94d933914bae7bd0179f8e4b681ed7f", + "validatorPublicKey": "0x8bfadd64382716c5dc45bd603ad47486563ca6bb1c628c428c7fc74e417063f1c839ef2c398bbf58aa5d477543427900", + "validatorPop": "0xa6587fed763a6d3a31fcc4615ef5da33420cc8f56041031b9b99584b16f1ea6998e804225a803a748a6d40fbe76210b501ae74756233b7fbb80f51287b905a885a6c617ebd3c888a6787b6762a57f30c10d2fbabea5acf65de976ae6ff5f4384" + }, + { + "mnemonic": "accusato peloso atono ingrosso drago ingaggio filo frugale legale bordo giocare merenda unicorno sillaba lentezza meschino nuvola invalido incluso lievito cronaca bruno pronome folclore", + "validatorPrivateKey": "6d1e23229f017876a276802df01e3b296d26e94ea3b20020a0539a8ad2dfc32e", + "validatorPublicKey": "0x8cba3304e81996eb5a4f054b621a7b69a8e100b0a0f6db862786c9353a6c5a42d35322b4fd18de84cca6dbfa4284874c", + "validatorPop": "0xb4f914d4990c00c45f96400b00a2b94954a4a9fe2f3b85b553650ef8c50387fe9806400a429d0a1e1ebcaeec3e2986430bb853b0d2c68126be66417f0c3bf786ce7eb22a605482f7d420e9163133a7f667bfb2aa4c037bbd03952a1abe66e11a" + }, + { + "mnemonic": "fisico briglia rimorchio dividere risata circa rizoma ammonito civetta orefice toccare pigro notturno plenario cedibile tacciare cardo affetto trachea delirio salgemma peccato orma rivincita", + "validatorPrivateKey": "4d760c6bdfdb94485e0632710029973d309ec39eb36f72ed299b7ee8760772e8", + "validatorPublicKey": "0xb0a15d79475eaf64f6b3fa0eb04baaeb6b45eba1fd416b6d41d886f31848a2103f743d41d81701e0ee924d07096d0c7f", + "validatorPop": "0x8dba6dcb0f9a51911a66c3b0896cec639f370ea40b8a854b234faca680f7b4362d863fc2b628794a485ef4c1892e291d04805b7560b449e6860ebca2560a5847f58406bb7eca0729a042bb1b0aab2afb57cb17e1af6048bff5d97f3cdf40b9b5" + }, + { + "mnemonic": "perdonato dormire brama golf laddove globulo pioggia piattino europa mittente disgelo rigettato udire pargolo rastrello oggetto incubo ausilio stirpe sfera croce solido accusato steppa", + "validatorPrivateKey": "5a983ba66a4e971c277cb34e44f7c8c6b6f4c689d7b3e9360b743b446dff3b56", + "validatorPublicKey": "0xb396b51daef875a1cdb81cf02d4049d13855e713698db8041b54d784927702f92ef09f0806da788162bbb6cb87ba24a3", + "validatorPop": "0x905e66bcdb09c30760bb74640e567984f976ad840321f84f4b8ba50651dfe5eba151464e6a11d8cf60bfcfa6bd2a511c0b95945b34c5326fd68bea8c0e6ce11195ace9e2cba5805e3b537ff3aa54b2660ceb897ba1b7fd5760f81d51d6883647" + } + ], + "spanish": [ + { + "mnemonic": "maíz encía sujeto pera tango espada atleta grueso cara abuso nómina elevar fracaso nieto género lino digno fábula oruga oriente pedir vitamina cinco tabla", + "validatorPrivateKey": "70b405bad8b30b77d4aff33adddc2c3821a8b30c08bfe99c115abaf08a8ccf6e", + "validatorPublicKey": "0xae4fbc7edb17c70d9aa22f3b4fae4866dc53c8c542b2a9049b11f466d63ccf8ed0bd08476b4bcaf1c80403120d8889c0", + "validatorPop": "0xa29fd2327fd5950eefb5c592772bdf25b7b8dd4536a7294d6dbabe08263af1080c2c318c791452b43664aeb60da78f761334dd1bb56130382107b7fe504e10d23b2f937c8f5a3cdc51134262ee0c370dc5d6e270d07e5f27f0a4e7419553f0ac" + }, + { + "mnemonic": "autor aseo jamón acción flor matar vulgar tejer nuera ronda apoyo mente agua kilo tapete pupa baño astro mazorca útil apoyo bestia ámbar uno", + "validatorPrivateKey": "15215ea82f34fbf37eb3ceec76daaf94b0d321e8c07d6c5fb5dcf084ee23cb8e", + "validatorPublicKey": "0x8e60ce19dc8ee0ca6dd7f6490cd8d313b0718b92c8784c4f2b6ffcf67e930a3b61ce516963d4138cb49275272e9c847a", + "validatorPop": "0xb143f1293a110c0ad56d2425a93ff271ac148a18c7dd63b8cb73984f0ecc32ab41789a9b0e1eea2c299b9147e345fdda08ef72b4ccf95110905d101aadae3e0843918552a244b79ea7792a570e6eafbf4ca1d8ee534cd872ab0286d68f311045" + }, + { + "mnemonic": "acné duque palpar abuelo evento tos torpedo fogata islote tocino huida usar observar potro lugar ronco padre lucir hogar fijar hígado evento pago motivo", + "validatorPrivateKey": "57a26f91b6d86457c0c7602d259c09e2bbf8e4da7cc79e61719d4910c63425b6", + "validatorPublicKey": "0xb9109ecf95afb9e483a44651db450a6a521a260401b53b7b558d25cf25f3cc9218b75200a47c1e3dba93a2b9a8d4d946", + "validatorPop": "0x970c2b22e5d3f2c66cf4a039d74eb3a60dcc1e309280f476d9e1c2cdec1d9934871cf20d90a225aa38e79f6bb6cc36dc01cb25ccb4e8dfa17227c9d0930e768643586c6ea8a21950d53b3154a3e22c866c5ac70281f0633aaadae6e10fb5240b" + }, + { + "mnemonic": "metro alejar máximo globo usar favor fracaso mes salón realidad sexo elipse margen superar asalto acelga anciano paquete lata cereza rico regreso fatiga fogata", + "validatorPrivateKey": "1a22998fffc2d23527c8de6e1f71c87b4fa8a12c3661839d1777e950aaf3ed26", + "validatorPublicKey": "0xabc04b56022055f74c91aa321f1bce9cd914f01e67ed3008b2448b0d9041074156d4cf944f502dd975bf9649ae7c9d0e", + "validatorPop": "0xb42dc75c320a3a0129f53b54ad8e6002dd8a95b484dcad02a95bcbc47b01d0a8820625c07fd963e32beb634b515383c602eeb074d20ca235778931d2efafb6d505c2196bf4f14dc1c946d88be912e9d22a5eed732bea12958950d6715088a08d" + }, + { + "mnemonic": "blanco escribir carbón arder llenar elipse seta opuesto sostén quemar vivir parar percha capitán acabar iris emoción laurel trauma joven seguir ropa lazo haz", + "validatorPrivateKey": "06b710058066d5e3b26a4c1891877a7b333a93bb8491d846bd322b77e1f94925", + "validatorPublicKey": "0xa1ab26d0ea3ff3d80764b10c5f5afb729457b37c07f4edf86d069148cb132bf7994ed27273fa4a5498d046e43822426f", + "validatorPop": "0x8c4400bee02a36e88476a45218cc391fc63c8cd93492d40a6ef9083fbbeed4ffb149d3c7e3761e97fb62426f1d0c08aa1225ed19ef8ddb80b3fe41ee7b7d63a9564f9435b2d292d692806cdecf999409a8ca9a51a331d719d3fee15297404050" + } + ], + "japanese": [ + { + "mnemonic": "いはん ことし いじょう はんい りれき てらす きない ふかい けいろ ぐうせい かいふく そっかん そまる ごうまん おおや だむる たぬき せんれい ろじうら くうぼ ことし たいおう しほう こふう", + "validatorPrivateKey": "1a051c7dddd9997f5175c50a19688e50774ea71beecbda2755f1a3ed72251573", + "validatorPublicKey": "0xa6ac75b094f23b3abb2d53ba413dcc3555e0f114fd6f43f3f461ba5ae1c4d0237ed86ee7ca26b2f6ad3f8830739c8148", + "validatorPop": "0x97262119a8a4ba92fe41b50ba19d09a0124c3910bf0f8f063b4784a389129b916a16f95d357541c5b72c11dce8d048b100a03bb7eb242b4101202b27cbc9d20e04937d265dfffc7da71a08313957224d7a5f2d410137f1a24bcb3c9c33ef4a27" + }, + { + "mnemonic": "ひんかく くふう にっけい うぶげ ゆそう やすたろう あんがい てつや ちあい いはつ あわせる ほかん ちりょう ひまん せびろ さうな さくら うやまう さばく ますく じむしょ みかん てのひら せんきょ", + "validatorPrivateKey": "2e3127928e4132fc4a2dcaa545793c8dddce684184a7eb6608d651f2a16db7fb", + "validatorPublicKey": "0xaad5e939d95ee279c215d6754064cbfb273753a7b455af53df76fb7c40c443dc97e55d8f32865d65a3db25bd9521c1ae", + "validatorPop": "0xabb1ed2deb2c0a4309d9535b38577f5696233bc938a745dc64f072dcf25658d11e60abb127faa74d2553dd21d7a0bda10fc066c52db7e41d011ff0c5c69f31f360f01b883bae752f9a519cd1c5fb93b78a72b05355fd84fe509971fe68dfe626" + }, + { + "mnemonic": "たべる ならび ひまん ひめじし ななおし ひしょ れいぞうこ けまり うえき みつかる ちつじょ めいえん しょうかい こおり けいれき だんち しゃたい つくる ていか まぬけ もんく つめたい おろす りれき", + "validatorPrivateKey": "4d1c867862ad583d3bb2d2d0c0a2ae0545654d17647bbe212f5ebedb7ca42d91", + "validatorPublicKey": "0x89ecf8433fb87c0a9be2e8fc634849150335ebe456fc5d9c9bd5c7fa3509b3188c84b0a85f80b6faf99db53794ac0aa7", + "validatorPop": "0xb396c3837230d6fbeb092d314e53f726705dff9ad0eb65719308ad81df19e74a5facc0808c53f0a827679fa5b97d1914068942744ac92554bca4ca7c1cc7c99a7113fb556155c5eebe8d0d5bc8fbdb31385ed60711f8e8d86e8e2612f794ed31" + }, + { + "mnemonic": "すぼん あつかう さとおや けなみ とおる だっしゅつ てんてき といれ いんよう きくらげ ふせい とおく たれる とおい こむぎこ おたがい にくまん ぎっちり そこそこ そっと わしつ にしき いろえんぴつ るすばん", + "validatorPrivateKey": "43e6f36d626653ace495db7ec22594bbd4263d41d027b63391022eb4e06f7bd0", + "validatorPublicKey": "0x93b14985bdbc07562b00a65af6b2aae357f0db463e74b3074427f7d671a1bc1bb93feff91308846a23d6e31d243e14d1", + "validatorPop": "0x860ba861cdb76dda0a61b634fec9f5421f69a66a49b1b92eeafd6ab23d712fe1d831c133749df1bbf7f28bef4a469f55149854a5a70761432c1db15d981834f6f16679c406f61c483439b8bad47907952b173e4261c0f4a7397570553f086fc4" + }, + { + "mnemonic": "ほっさ ふんしつ いわい せんさい せまい はやし みてい まんぞく ちいさい なまえ ざつがく てあみ こんれい はいち おろす たいえき くどく いたずら まねく こたつ がっこう おかえり てんめつ せんちょう", + "validatorPrivateKey": "6e651b09fb37b34f167fbef154b02c21df3b0befa628123a5ca5892b3096482e", + "validatorPublicKey": "0x88755c8f172438ee524351f3fbc7df85a536bb6b6a15a0cfcda60ce63eb3003c5cfbb3f7161021500cb6afe08b845fbd", + "validatorPop": "0x8a5867a775ee373be5f706dc6619f1527dd2f0ceef0103100a614617deec9d72b2e5d8559599dede83bdc4b044592597055fcf761a2d06fde89c6f817be3d539e5ca39dcb4fad6a48bfc96d3e8ebf873e2a244a039354bfbd642c89f5d9f5f21" + } + ], + "portuguese": [ + { + "mnemonic": "empurrar jangada bajular cratera imenso hidratar prensar outono oriental pires carreira tamborim amolador mexer tinteiro produto tenente pedestre advogado rupestre grelhar populoso indutor igreja", + "validatorPrivateKey": "6cd1e26fe4b60cdacec4fbbf4a69be53084ac1bf776f982d5bc3b5ddb1191620", + "validatorPublicKey": "0x855fb0ffd9d7c8d97c94093eaba87e31a9ee496a2234c02448d6b2004958306c1d5b9582adc1f982f4ea931569af460e", + "validatorPop": "0xa2e75834a16c982391bd423ecd3985eeac8e368507e6038fee8ec8191fe97269e0db822660dd70e353bf960c5fc320d61059366e2d16e2a2a2d9c271026030dec6af4e29f8c446f60b637c33fa7e7322cc6e2a0683831aad96ea37165e4a9bc1" + }, + { + "mnemonic": "damasco visto duelar cruzeiro repleto avulso esteira magreza quimono esfumado sono guarani prece pasmo enfeite atarefar selvagem vigorar vestido sinal foguete silicone apanhado focal", + "validatorPrivateKey": "5343c9ca5f432b8adb57295480e40e2768ee81ac4bed1c00003314cae960f9a7", + "validatorPublicKey": "0x80ec1e2fe666acc1fb58727f71ca59599cf7444266d953de513c893bb242854c72b615bfd7335cc621963f57a62c739f", + "validatorPop": "0xadb86bf20d58a9930dac234b49104f51fcdf4264bd504ed7afc735a89830fa3d0590e5255631938af8944d094e16d79e0a514f33c1eee477d377289bc11280c9c12805839b47467b36e1a1cc48e6ab75f2e6d5b0016e9a05b43827acd490f788" + }, + { + "mnemonic": "medida genoma solda deboche corvo lucidez ciente genoma papelada muralha atracar expandir honesto guiar donativo careca surdina pantanal carbono vigorar triplo toxina peculiar piranha", + "validatorPrivateKey": "0206938e176266422b3c1f21c904e707653f299e516482717ef5f0e566a19ae8", + "validatorPublicKey": "0xb0665a81085b96a6c0c459e5dab927a49878c18aaa6e7086efcaeb6f53c5590636d2b41c0834af4884ddc5afc6d9c5c8", + "validatorPop": "0xa828d7b90866bb764113b4b669d71328225250d21725b7c4942500c41b41367418511b0dbbc86b17baa171552e218fdf01740d3f1a9fb608dfe42c3a456d85dd588f8b29eeb45440348e4d0b29d31b239383d607a3f4df0ce99bba8053f9be41" + }, + { + "mnemonic": "firmeza bovino captador sovado roncar pupilo gralha raiva edital relativo voar ventre censo ilustrar aclive membro negativa copeiro copiador patamar incenso sozinho chover refogar", + "validatorPrivateKey": "71195017204610b004b5030d0cee33ac0c7d0bd95b33d89f93c7b61746812936", + "validatorPublicKey": "0x813c929f451a522de69e36ff7e94ca3c6d34123e3050110e1a47a215e0beeae8e0eaf438a5dc8851f0a748c4587821b8", + "validatorPop": "0xb486b3bd7e6ef57a186b798dbb446e3102fdc396a98b18acad0d2b31eb957925c3b067511755ebedd5705a1ed3fa28ad1883be3d9511f7a691d3e5672590ad665e838968cc0c2f6ba28204683eb1719833fa84cd2e90c6b5eae6fea8b9adfdfa" + }, + { + "mnemonic": "abaixo louvar navio matutar duelar cirurgia notar infrator noiva esponja afastar moqueca viveiro envergar litoral tijolo coquetel arara ambiente germinar emulador enlatar esfolar veicular", + "validatorPrivateKey": "2d5aa4d2cbfc4c85f889a55b7be68b5d36c7c3d5a960509fa6b809bd319c4a87", + "validatorPublicKey": "0xa4670f07064f089d9157197cb6357bd58f099ba81db516cbb8e3642e433e529de843937896463845d615edf009223c4b", + "validatorPop": "0xa23094dce8e0af71a400344cfa63fd46735e9db1ca7bd0a0ec034ae1313dbba15f59cb21728852b07f4c956af2982db6116ea39de2e4db3500684f4d822859ab9ee55d6ed84da54e8c5b4fcb20f70fe431fecf0d414cfbd1bcc66516438d1acc" + } + ], + "english": [ + { + "mnemonic": "know blame layer barrel achieve wrap crystal attack mystery manual fragile decline grab tennis model lift hen slush memory wear hobby soup major fluid", + "validatorPrivateKey": "16c24bbc9fb2741f47a7ed5f37aeb59ef9444fbadaa3008eecb7964659899099", + "validatorPublicKey": "0xaa52febae59e6068a1d9527733553ed9427eee40b42d5ac745371dcc4618c47f11b811cba6beed1fed575fc401a89ba4", + "validatorPop": "0xa763308ba9149bca48e7cccd6047e970c249cdaae339f355c60667497a5a803e51749c162bea375edd94574447a7396d0df9c4ef57245bc105f1c9375f79f0dfccfa8df76b9e524529bf556b17bd81e0576fbaa4806355c3629f26f47d01295d" + }, + { + "mnemonic": "device cart aware icon joke taste inject goose degree various oven menu obey ride enemy find flush ribbon orbit thank zero protect tail fresh", + "validatorPrivateKey": "13f4a2433ac8c56eafd74a242f34ab650c4756bb4ce01fd4cc79d7889777e374", + "validatorPublicKey": "0xaf835876f9a6578b6e8fd9dc811d42927eab7fd426a3094d4c98203280137117381857d4d6d083caa2dce34e98c85a91", + "validatorPop": "0x8676e292790d03a51f59fc94d86dd572c5d5c0d4ffc8beeb434e0f6e31053631b5076d02ddc544cfbf1f0d1547cf8e1c105f60afd0f9c4dcb1cd96be39259999dabeecf2b60df77ca31e0bc3b406d049ad82ef89e9bd8b4af57547150d3483a5" + }, + { + "mnemonic": "during menu novel beach project total place embrace language pumpkin bag trap survey afraid maze gorilla vast bacon hole poverty recipe treat jewel sustain", + "validatorPrivateKey": "55bff2f1883b1bbc4a34c8e145af725cf0f93da28edb11f104bd1a688872d9cb", + "validatorPublicKey": "0x95f332e9b984babbd76c2d573b6dda8c1ab44732ed078b1a9e7760925c885acb023ec9a58041f6142068320d976a2c2e", + "validatorPop": "0xaa23783e6a5a2e03d6db9fe746072fd48834bd6d06b5e22f696b58f4badd6bb9eb1feb92df67f8d0d256cca678f41a970591a9d56fc00e8ebf8866bc775af86caca7ebbbf44d98f36ffb6ffc82c866f471fea1c21c3a75ec128eb42fd4591563" + }, + { + "mnemonic": "purse wrist scissors matter blanket stumble square notice dirt bounce cross table earn hockey retreat ridge lake wage comfort truly write select buffalo place", + "validatorPrivateKey": "53b0a649d988a38e074596a052a613abd35ca3b0c8dd98d6da4e4765162933f3", + "validatorPublicKey": "0xb92f8b7a2c83a9a508039e98caa647f17ef42585b8140b8e2b542b5c32806730e03402d767b2e19f629b90981f6a1020", + "validatorPop": "0xb0349a73f2cf56dae41d5b72b2136926c988b43fb3dd89de7248b74eb1ed0463b06de3f7c6bb367b734c0360022946261763c43f7817ab34dc25e043c2209993f1d47495a324c01bc7fb783388dd984be955937ba150cb07c555c1d3529d036f" + }, + { + "mnemonic": "salmon bunker faint disagree cruise spin soon spider number pudding drift super behind melody slot top leopard odor cheese tomato roof wonder off filter", + "validatorPrivateKey": "3e12e7627f215132fd14003f996844de67f90f51ad5e5c98374f684cb77e0717", + "validatorPublicKey": "0x8253ba7a64fbea2746e04274ffbead5c19492af8fb6aecfc84a8348b8d116fb59d9e125d2e713fa73f02b1d9037ab5aa", + "validatorPop": "0xa0f8cb0113f6975a434fb1d8e30f15ad3c8d8c9a3862f648f227cb5b5d168843bbae3f3bec10f0db81d1038266891eee0e8261c5e5689098a83cdf86d5fbf3afe1eb1b511bf8c7aea224b1856940471923a223fded43919b01f44c2b85b33005" + } + ] +}