diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 000000000..4f21fd92a --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,26 @@ +name: Backport +on: + pull_request_target: + types: + - closed + - labeled + +jobs: + backport: + name: Backport + runs-on: ubuntu-latest + # Only react to merged PRs for security reasons. + # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. + if: > + github.event.pull_request.merged + && ( + github.event.action == 'closed' + || ( + github.event.action == 'labeled' + && contains(github.event.label.name, 'backport') + ) + ) + steps: + - uses: tibdex/backport@9565281eda0731b1d20c4025c43339fb0a23812e + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 817fd3f6e..69e37a9fe 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -131,9 +131,22 @@ jobs: run: | echo "PERL=$(which perl)" >> $GITHUB_ENV echo "OPENSSL_SRC_PERL=$(which perl)" >> $GITHUB_ENV - choco install openssl --version 3.4.1 --install-arguments="'/DIR=C:\OpenSSL'" -y - echo "OPENSSL_LIB_DIR=C:\OpenSSL\lib\VC\x64\MT" >> $GITHUB_ENV - echo "OPENSSL_INCLUDE_DIR=C:\OpenSSL\include" >> $GITHUB_ENV + cat > vcpkg.json <> $GITHUB_ENV + echo "OPENSSL_INCLUDE_DIR=$GITHUB_WORKSPACE/vcpkg_installed/x64-windows-static-md/include" >> $GITHUB_ENV - name: Run clippy shell: bash @@ -364,7 +377,9 @@ jobs: - name: Setup Environment uses: ./.github/actions/setup with: - stable-toolchain: true + nightly-toolchain: true + cargo-cache-key: cargo-sbf-build + cargo-cache-fallback-key: cargo-sbf - name: Determine Solana CLI version run: | @@ -378,9 +393,37 @@ jobs: version: ${{ env.SOLANA_VERSION }} cache: true + - name: Install cargo-hack + uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: cargo-hack + - name: Run cargo-build-sbf run: ./scripts/build-sbf.sh + test-doc: + name: Cargo run doctests + runs-on: ubuntu-latest + needs: [check] + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + nightly-toolchain: true + cargo-cache-key: cargo-nightly-doc + cargo-cache-fallback-key: cargo-nightly + + - name: Install cargo-hack + uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: cargo-hack + + - name: Run doc tests + run: ./scripts/test-doc.sh + miri: name: Test miri runs-on: ubuntu-latest diff --git a/.github/workflows/publish-rust.yml b/.github/workflows/publish-rust.yml index b010b9046..15033cd16 100644 --- a/.github/workflows/publish-rust.yml +++ b/.github/workflows/publish-rust.yml @@ -190,7 +190,7 @@ jobs: uses: orhun/git-cliff-action@v4 with: config: "scripts/cliff.toml" - args: ${{ steps.publish.outputs.old_git_tag }}..master --include-path "${{ inputs.package_path }}/**" --github-repo ${{ github.repository }} + args: ${{ steps.publish.outputs.old_git_tag }}..HEAD --include-path "${{ inputs.package_path }}/**" --github-repo ${{ github.repository }} env: OUTPUT: TEMP_CHANGELOG.md GITHUB_REPO: ${{ github.repository }} diff --git a/Cargo.lock b/Cargo.lock index f7b848504..e651b59ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -60,17 +59,61 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.59.0", +] [[package]] name = "anyhow" -version = "1.0.96" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -120,7 +163,7 @@ dependencies = [ "ark-serialize", "ark-std", "derivative", - "digest 0.10.7", + "digest", "itertools 0.10.5", "num-bigint", "num-traits", @@ -173,7 +216,7 @@ checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-serialize-derive", "ark-std", - "digest 0.10.7", + "digest", "num-bigint", ] @@ -195,7 +238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.5", + "rand", ] [[package]] @@ -236,17 +279,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.4.0" @@ -269,10 +301,10 @@ dependencies = [ ] [[package]] -name = "base64" -version = "0.12.3" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" @@ -286,6 +318,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bincode" version = "1.3.3" @@ -319,6 +357,18 @@ dependencies = [ "typenum", ] +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "blake3" version = "1.5.5" @@ -330,35 +380,44 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "digest 0.10.7", + "digest", ] [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] -name = "block-buffer" -version = "0.10.4" +name = "blst" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "47c79a94619fade3c0b887670333513a67ac28a6a7e653eb260bf0d4103db38d" dependencies = [ - "generic-array", + "cc", + "glob", + "threadpool", + "zeroize", ] [[package]] -name = "borsh" -version = "0.10.4" +name = "blstrs" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" dependencies = [ - "borsh-derive 0.10.4", - "hashbrown 0.13.2", + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core", + "serde", + "subtle", ] [[package]] @@ -367,23 +426,10 @@ version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc" dependencies = [ - "borsh-derive 1.5.5", + "borsh-derive", "cfg_aliases", ] -[[package]] -name = "borsh-derive" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "borsh-derive" version = "1.5.5" @@ -391,33 +437,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8b668d39970baad5356d7c83a86fee3a539e6f93bf6764c97368243e17a0487" dependencies = [ "once_cell", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.98", ] [[package]] -name = "borsh-derive-internal" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.4" +name = "boxcar" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf" [[package]] name = "brotli" @@ -465,11 +495,17 @@ dependencies = [ "serde", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ "bytemuck_derive", ] @@ -573,18 +609,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.27" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.27" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstyle", "clap_lex", @@ -596,6 +632,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "console" version = "0.15.10" @@ -629,6 +671,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "constant_time_eq" version = "0.3.1" @@ -737,36 +785,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.8.0" +name = "crypto-bigint" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", + "rand_core", "subtle", + "zeroize", ] [[package]] -name = "curve25519-dalek" -version = "3.2.1" +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", + "generic-array", + "typenum", ] [[package]] @@ -778,9 +815,9 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest 0.10.7", + "digest", "fiat-crypto", - "rand_core 0.6.4", + "rand_core", "rustc_version", "subtle", "zeroize", @@ -843,6 +880,17 @@ dependencies = [ "lock_api", "once_cell", "parking_lot_core", + "serde", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", ] [[package]] @@ -873,22 +921,14 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -904,39 +944,55 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "ed25519" -version = "1.5.3" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ + "pkcs8", "signature", ] [[package]] name = "ed25519-dalek" -version = "1.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ - "curve25519-dalek 3.2.1", + "curve25519-dalek", "ed25519", - "rand 0.7.3", + "rand_core", "serde", - "sha2 0.9.9", + "sha2", + "subtle", "zeroize", ] [[package]] name = "ed25519-dalek-bip32" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +checksum = "6b49a684b133c4980d7ee783936af771516011c8cd15f429dbda77245e282f03" dependencies = [ "derivation-path", "ed25519-dalek", - "hmac 0.12.1", - "sha2 0.10.8", + "hmac", + "sha2", ] [[package]] @@ -945,6 +1001,25 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encode_unicode" version = "1.0.0" @@ -961,16 +1036,26 @@ dependencies = [ ] [[package]] -name = "env_logger" -version = "0.9.3" +name = "env_filter" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ - "atty", - "humantime", "log", "regex", - "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", ] [[package]] @@ -979,12 +1064,39 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "feature-probe" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1055,6 +1167,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.31" @@ -1140,32 +1258,32 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", - "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -1174,6 +1292,25 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand", + "rand_core", + "rand_xorshift", + "subtle", +] + [[package]] name = "h2" version = "0.3.26" @@ -1195,9 +1332,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -1232,18 +1369,15 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "hex" @@ -1251,34 +1385,13 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array", - "hmac 0.8.1", + "digest", ] [[package]] @@ -1315,12 +1428,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "0.14.32" @@ -1511,7 +1618,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ "bitmaps", - "rand_core 0.6.4", + "rand_core", "rand_xoshiro", "rayon", "serde", @@ -1551,15 +1658,21 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "is-terminal" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi 0.5.1", "libc", "windows-sys 0.59.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -1584,6 +1697,30 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -1594,6 +1731,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + [[package]] name = "keccak" version = "0.1.5" @@ -1616,52 +1767,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] -name = "libsecp256k1" -version = "0.6.0" +name = "linux-raw-sys" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" -dependencies = [ - "arrayref", - "base64 0.12.3", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "typenum", -] - -[[package]] -name = "libsecp256k1-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" -dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" -dependencies = [ - "libsecp256k1-core", -] +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -1774,6 +1883,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + [[package]] name = "num_enum" version = "0.7.3" @@ -1789,7 +1908,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.98", @@ -1812,21 +1931,21 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "oorandom" -version = "11.1.4" +name = "once_cell_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] -name = "opaque-debug" -version = "0.3.1" +name = "oorandom" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "openssl" @@ -1876,6 +1995,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1907,20 +2035,21 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" -version = "0.4.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "crypto-mac", + "digest", ] [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest 0.10.7", + "digest", + "hmac", ] [[package]] @@ -1941,6 +2070,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.31" @@ -1982,21 +2121,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] -name = "ppv-lite86" -version = "0.2.20" +name = "portable-atomic-util" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" dependencies = [ - "zerocopy", + "portable-atomic", ] [[package]] -name = "proc-macro-crate" -version = "0.1.5" +name = "ppv-lite86" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "toml 0.5.11", + "zerocopy", ] [[package]] @@ -2047,17 +2186,16 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.7.3" +name = "r-efi" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" @@ -2066,18 +2204,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -2087,16 +2215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -2109,12 +2228,12 @@ dependencies = [ ] [[package]] -name = "rand_hc" -version = "0.2.0" +name = "rand_xorshift" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.5.1", + "rand_core", ] [[package]] @@ -2123,7 +2242,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -2227,6 +2346,16 @@ dependencies = [ "winreg", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.13" @@ -2262,6 +2391,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.8.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + [[package]] name = "rustls" version = "0.21.12" @@ -2330,6 +2472,20 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "semver" version = "1.0.25" @@ -2338,9 +2494,9 @@ checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -2365,9 +2521,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -2388,9 +2544,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -2455,19 +2611,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.8" @@ -2476,7 +2619,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -2485,7 +2628,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.7", + "digest", "keccak", ] @@ -2516,9 +2659,13 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.4" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] [[package]] name = "siphasher" @@ -2575,7 +2722,7 @@ dependencies = [ "solana-clock", "solana-frozen-abi", "solana-frozen-abi-macro", - "solana-instruction", + "solana-instruction-error", "solana-logger", "solana-pubkey", "solana-sdk-ids", @@ -2593,6 +2740,39 @@ dependencies = [ "solana-pubkey", ] +[[package]] +name = "solana-address" +version = "0.1.0" +dependencies = [ + "anyhow", + "arbitrary", + "borsh", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "five8", + "five8_const", + "rand", + "serde", + "serde_derive", + "solana-account-info", + "solana-address", + "solana-atomic-u64", + "solana-cpi", + "solana-define-syscall", + "solana-example-mocks", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-hash", + "solana-instruction", + "solana-program-error", + "solana-sanitize", + "solana-sha256-hasher", + "solana-system-interface", + "strum", + "strum_macros", +] + [[package]] name = "solana-address-lookup-table-interface" version = "2.2.2" @@ -2607,6 +2787,7 @@ dependencies = [ "solana-frozen-abi-macro", "solana-hash", "solana-instruction", + "solana-instruction-error", "solana-pubkey", "solana-sdk-ids", "solana-slot-hashes", @@ -2614,7 +2795,7 @@ dependencies = [ [[package]] name = "solana-atomic-u64" -version = "2.2.1" +version = "3.0.0" dependencies = [ "parking_lot", ] @@ -2624,6 +2805,7 @@ name = "solana-big-mod-exp" version = "2.2.1" dependencies = [ "array-bytes", + "criterion", "num-bigint", "num-traits", "serde", @@ -2638,7 +2820,7 @@ version = "2.2.1" dependencies = [ "bincode", "serde", - "solana-instruction", + "solana-instruction-error", "solana-system-interface", ] @@ -2647,16 +2829,39 @@ name = "solana-blake3-hasher" version = "2.2.1" dependencies = [ "blake3", - "borsh 1.5.5", - "bs58", - "serde", - "serde_derive", "solana-blake3-hasher", "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-bls-signatures" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "bincode", + "blst", + "blstrs", + "bytemuck", + "cfg_eval", + "criterion", + "ff", + "group", + "pairing", + "rand", + "rayon", + "serde", + "serde_json", + "serde_with", + "solana-bls-signatures", "solana-frozen-abi", "solana-frozen-abi-macro", - "solana-hash", - "solana-sanitize", + "solana-keypair", + "solana-signature", + "solana-signer", + "subtle", + "tempfile", + "thiserror 2.0.12", ] [[package]] @@ -2674,15 +2879,14 @@ dependencies = [ "serde_derive", "serde_json", "solana-define-syscall", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] name = "solana-borsh" -version = "2.2.1" +version = "3.0.0" dependencies = [ - "borsh 0.10.4", - "borsh 1.5.5", + "borsh", ] [[package]] @@ -2730,7 +2934,7 @@ dependencies = [ [[package]] name = "solana-commitment-config" -version = "2.2.1" +version = "3.0.0" dependencies = [ "serde", "serde_derive", @@ -2740,7 +2944,7 @@ dependencies = [ name = "solana-compute-budget-interface" version = "2.2.2" dependencies = [ - "borsh 1.5.5", + "borsh", "serde", "serde_derive", "solana-frozen-abi", @@ -2765,21 +2969,13 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "solana-decode-error" -version = "2.3.0" -dependencies = [ - "num-derive", - "num-traits", -] - [[package]] name = "solana-define-syscall" -version = "2.3.0" +version = "3.0.0" [[package]] name = "solana-derivation-path" -version = "2.2.1" +version = "3.0.0" dependencies = [ "assert_matches", "derivation-path", @@ -2793,23 +2989,13 @@ version = "2.2.3" dependencies = [ "bytemuck", "bytemuck_derive", - "ed25519-dalek", - "hex", - "rand 0.7.3", - "solana-feature-set", - "solana-hash", "solana-instruction", - "solana-keypair", - "solana-logger", - "solana-precompile-error", - "solana-sdk", "solana-sdk-ids", - "solana-signer", ] [[package]] name = "solana-epoch-info" -version = "2.2.1" +version = "3.0.0" dependencies = [ "serde", "serde_derive", @@ -2855,6 +3041,14 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "solana-epoch-stake" +version = "2.2.1" +dependencies = [ + "solana-define-syscall", + "solana-pubkey", +] + [[package]] name = "solana-example-mocks" version = "2.2.1" @@ -2871,7 +3065,7 @@ dependencies = [ "solana-pubkey", "solana-sdk-ids", "solana-system-interface", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -2892,30 +3086,6 @@ dependencies = [ "solana-system-interface", ] -[[package]] -name = "solana-feature-set" -version = "2.2.5" -dependencies = [ - "ahash", - "lazy_static", - "solana-epoch-schedule", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-hash", - "solana-pubkey", - "solana-sha256-hasher", -] - -[[package]] -name = "solana-feature-set-interface" -version = "4.0.1" -dependencies = [ - "ahash", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-pubkey", -] - [[package]] name = "solana-fee-calculator" version = "2.2.1" @@ -2937,13 +3107,11 @@ dependencies = [ "serde", "serde_derive", "solana-frozen-abi", - "solana-message", - "solana-native-token", ] [[package]] name = "solana-file-download" -version = "2.2.2" +version = "3.0.0" dependencies = [ "console", "indicatif", @@ -2953,12 +3121,14 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "2.2.2" +version = "3.0.0" dependencies = [ "bitflags 2.8.0", + "boxcar", "bs58", "bv", "bytes", + "dashmap", "im", "log", "memmap2", @@ -2966,15 +3136,15 @@ dependencies = [ "serde_bytes", "serde_derive", "serde_with", - "sha2 0.10.8", + "sha2", "solana-frozen-abi-macro", "solana-logger", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] name = "solana-frozen-abi-macro" -version = "2.2.1" +version = "3.0.0" dependencies = [ "proc-macro2", "quote", @@ -3026,19 +3196,17 @@ dependencies = [ name = "solana-hash" version = "2.3.0" dependencies = [ - "borsh 1.5.5", + "borsh", "bs58", "bytemuck", "bytemuck_derive", "five8", - "js-sys", "serde", "serde_derive", "solana-atomic-u64", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-sanitize", - "wasm-bindgen", ] [[package]] @@ -3056,18 +3224,27 @@ name = "solana-instruction" version = "2.3.0" dependencies = [ "bincode", - "borsh 1.5.5", - "getrandom 0.2.15", - "js-sys", - "num-traits", + "borsh", "serde", "serde_derive", "solana-define-syscall", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-instruction", + "solana-instruction-error", "solana-pubkey", - "wasm-bindgen", +] + +[[package]] +name = "solana-instruction-error" +version = "1.0.0" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-program-error", ] [[package]] @@ -3078,6 +3255,7 @@ dependencies = [ "qualifier_attr", "solana-account-info", "solana-instruction", + "solana-instruction-error", "solana-program-error", "solana-pubkey", "solana-sanitize", @@ -3090,15 +3268,9 @@ dependencies = [ name = "solana-keccak-hasher" version = "2.2.1" dependencies = [ - "borsh 1.5.5", - "serde", - "serde_derive", "sha3", "solana-define-syscall", - "solana-frozen-abi", - "solana-frozen-abi-macro", "solana-hash", - "solana-sanitize", ] [[package]] @@ -3108,7 +3280,7 @@ dependencies = [ "ed25519-dalek", "ed25519-dalek-bip32", "five8", - "rand 0.7.3", + "rand", "serde_json", "solana-derivation-path", "solana-pubkey", @@ -3118,7 +3290,6 @@ dependencies = [ "solana-signer", "static_assertions", "tiny-bip39", - "wasm-bindgen", ] [[package]] @@ -3180,7 +3351,7 @@ dependencies = [ [[package]] name = "solana-logger" -version = "2.3.1" +version = "3.0.0" dependencies = [ "env_logger", "lazy_static", @@ -3197,43 +3368,41 @@ dependencies = [ "bincode", "bitflags 2.8.0", "blake3", - "borsh 1.5.5", + "borsh", "itertools 0.12.1", "lazy_static", "serde", "serde_derive", "serde_json", - "solana-bincode", - "solana-frozen-abi", + "solana-address-lookup-table-interface", + "solana-example-mocks", + "solana-frozen-abi", "solana-frozen-abi-macro", "solana-hash", "solana-instruction", + "solana-instruction-error", "solana-logger", "solana-message", "solana-nonce", - "solana-program", "solana-pubkey", "solana-sanitize", "solana-sdk-ids", - "solana-sha256-hasher", "solana-short-vec", "solana-system-interface", - "solana-sysvar", "solana-transaction-error", "static_assertions", - "wasm-bindgen", ] [[package]] name = "solana-msg" -version = "2.2.1" +version = "3.0.0" dependencies = [ "solana-define-syscall", ] [[package]] name = "solana-native-token" -version = "2.3.0" +version = "3.0.0" [[package]] name = "solana-nonce" @@ -3288,12 +3457,12 @@ dependencies = [ [[package]] name = "solana-package-metadata-macro" -version = "2.2.1" +version = "3.0.0" dependencies = [ "proc-macro2", "quote", "syn 2.0.98", - "toml 0.8.20", + "toml", ] [[package]] @@ -3326,25 +3495,9 @@ dependencies = [ [[package]] name = "solana-precompile-error" -version = "2.2.2" +version = "3.0.0" dependencies = [ "num-traits", - "solana-decode-error", -] - -[[package]] -name = "solana-precompiles" -version = "2.2.2" -dependencies = [ - "lazy_static", - "solana-ed25519-program", - "solana-feature-set", - "solana-message", - "solana-precompile-error", - "solana-pubkey", - "solana-sdk-ids", - "solana-secp256k1-program", - "solana-secp256r1-program", ] [[package]] @@ -3361,61 +3514,29 @@ dependencies = [ name = "solana-program" version = "2.3.0" dependencies = [ - "arbitrary", - "array-bytes", - "assert_matches", - "bincode", - "blake3", - "borsh 0.10.4", - "borsh 1.5.5", - "bs58", - "bytemuck", - "console_error_panic_hook", - "console_log", - "getrandom 0.2.15", - "itertools 0.12.1", - "lazy_static", - "log", "memoffset", - "num-bigint", - "num-derive", - "num-traits", - "rand 0.8.5", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", "solana-account-info", - "solana-address-lookup-table-interface", - "solana-atomic-u64", "solana-big-mod-exp", - "solana-bincode", "solana-blake3-hasher", "solana-borsh", "solana-clock", "solana-cpi", - "solana-decode-error", "solana-define-syscall", "solana-epoch-rewards", "solana-epoch-schedule", + "solana-epoch-stake", "solana-example-mocks", - "solana-feature-gate-interface", "solana-fee-calculator", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-hash", "solana-instruction", + "solana-instruction-error", "solana-instructions-sysvar", "solana-keccak-hasher", "solana-last-restart-slot", - "solana-loader-v2-interface", - "solana-loader-v3-interface", - "solana-loader-v4-interface", - "solana-logger", - "solana-message", "solana-msg", "solana-native-token", - "solana-nonce", "solana-program-entrypoint", "solana-program-error", "solana-program-memory", @@ -3423,9 +3544,7 @@ dependencies = [ "solana-program-pack", "solana-pubkey", "solana-rent", - "solana-sanitize", "solana-sdk-ids", - "solana-sdk-macro", "solana-secp256k1-recover", "solana-serde-varint", "solana-serialize-utils", @@ -3434,13 +3553,9 @@ dependencies = [ "solana-slot-hashes", "solana-slot-history", "solana-stable-layout", - "solana-stake-interface", "solana-system-interface", "solana-sysvar", "solana-sysvar-id", - "solana-vote-interface", - "thiserror 2.0.11", - "wasm-bindgen", ] [[package]] @@ -3448,6 +3563,7 @@ name = "solana-program-entrypoint" version = "2.3.0" dependencies = [ "solana-account-info", + "solana-define-syscall", "solana-msg", "solana-program-error", "solana-pubkey", @@ -3455,28 +3571,24 @@ dependencies = [ [[package]] name = "solana-program-error" -version = "2.2.2" +version = "3.0.0" dependencies = [ - "borsh 1.5.5", - "num-traits", + "borsh", + "num_enum", "serde", "serde_derive", - "solana-decode-error", - "solana-instruction", - "solana-msg", - "solana-pubkey", ] [[package]] name = "solana-program-memory" -version = "2.3.1" +version = "3.0.0" dependencies = [ "solana-define-syscall", ] [[package]] name = "solana-program-option" -version = "2.2.1" +version = "3.0.0" [[package]] name = "solana-program-pack" @@ -3489,39 +3601,13 @@ dependencies = [ name = "solana-pubkey" version = "2.4.0" dependencies = [ - "anyhow", - "arbitrary", - "borsh 0.10.4", - "borsh 1.5.5", - "bs58", - "bytemuck", - "bytemuck_derive", - "curve25519-dalek 4.1.3", - "five8", - "five8_const", - "getrandom 0.2.15", - "js-sys", - "num-traits", - "rand 0.8.5", - "serde", - "serde_derive", - "solana-atomic-u64", - "solana-decode-error", - "solana-define-syscall", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-program", - "solana-pubkey", - "solana-sanitize", - "solana-sha256-hasher", - "strum", - "strum_macros", - "wasm-bindgen", + "rand", + "solana-address", ] [[package]] name = "solana-quic-definitions" -version = "2.3.0" +version = "2.3.1" dependencies = [ "solana-keypair", ] @@ -3560,28 +3646,6 @@ dependencies = [ "solana-sdk-ids", ] -[[package]] -name = "solana-rent-debits" -version = "2.2.1" -dependencies = [ - "solana-pubkey", - "solana-reward-info", -] - -[[package]] -name = "solana-reserved-account-keys" -version = "2.2.2" -dependencies = [ - "lazy_static", - "solana-feature-set", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-message", - "solana-pubkey", - "solana-sdk-ids", - "solana-sysvar", -] - [[package]] name = "solana-reward-info" version = "2.2.1" @@ -3594,7 +3658,7 @@ dependencies = [ [[package]] name = "solana-sanitize" -version = "2.2.1" +version = "3.0.0" [[package]] name = "solana-sdk" @@ -3602,60 +3666,24 @@ version = "2.3.0" dependencies = [ "bincode", "bs58", - "curve25519-dalek 4.1.3", - "ed25519-dalek", - "getrandom 0.1.16", - "js-sys", - "libsecp256k1", - "openssl", - "rand 0.7.3", "serde", - "serde_derive", - "serde_json", - "serde_with", "solana-account", - "solana-bn254", - "solana-client-traits", - "solana-cluster-type", - "solana-commitment-config", - "solana-compute-budget-interface", - "solana-decode-error", - "solana-derivation-path", - "solana-ed25519-program", "solana-epoch-info", "solana-epoch-rewards-hasher", - "solana-feature-set", "solana-fee-structure", - "solana-genesis-config", - "solana-hard-forks", "solana-inflation", - "solana-instruction", "solana-instructions-sysvar", "solana-keypair", "solana-message", - "solana-native-token", - "solana-nonce-account", "solana-offchain-message", - "solana-packet", - "solana-poh-config", - "solana-precompile-error", - "solana-precompiles", "solana-presigner", "solana-program", "solana-program-memory", "solana-pubkey", - "solana-quic-definitions", - "solana-rent-collector", - "solana-rent-debits", - "solana-reserved-account-keys", - "solana-reward-info", "solana-sanitize", "solana-sdk", "solana-sdk-ids", "solana-sdk-macro", - "solana-secp256k1-program", - "solana-secp256k1-recover", - "solana-secp256r1-program", "solana-seed-derivable", "solana-seed-phrase", "solana-serde", @@ -3664,14 +3692,10 @@ dependencies = [ "solana-shred-version", "solana-signature", "solana-signer", - "solana-system-transaction", "solana-time-utils", "solana-transaction", - "solana-transaction-context", "solana-transaction-error", - "solana-validator-exit", - "thiserror 2.0.11", - "wasm-bindgen", + "thiserror 2.0.12", ] [[package]] @@ -3683,7 +3707,7 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "2.2.1" +version = "3.0.0" dependencies = [ "bs58", "proc-macro2", @@ -3691,35 +3715,61 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "solana-sdk-wasm-js" +version = "1.0.0" +dependencies = [ + "bincode", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.15", + "js-sys", + "log", + "solana-address", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-signature", + "solana-signer", + "solana-transaction", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-wasm-js-tests" +version = "1.0.0" +dependencies = [ + "js-sys", + "solana-address", + "solana-instruction", + "solana-sdk-wasm-js", + "wasm-bindgen", +] + [[package]] name = "solana-secp256k1-program" version = "2.2.3" dependencies = [ "anyhow", "bincode", - "digest 0.10.7", + "digest", "hex", - "libsecp256k1", - "rand 0.7.3", + "k256", + "rand", "serde", "serde_derive", "sha3", "solana-account-info", - "solana-feature-set", - "solana-hash", + "solana-example-mocks", "solana-instruction", "solana-instructions-sysvar", "solana-keccak-hasher", - "solana-keypair", - "solana-logger", "solana-msg", - "solana-precompile-error", "solana-program-error", - "solana-sdk", "solana-sdk-ids", "solana-secp256k1-program", "solana-signature", - "solana-signer", ] [[package]] @@ -3727,13 +3777,14 @@ name = "solana-secp256k1-recover" version = "2.2.1" dependencies = [ "anyhow", - "borsh 1.5.5", - "libsecp256k1", + "borsh", + "k256", + "rand", "solana-define-syscall", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-program", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -3742,11 +3793,7 @@ version = "2.2.4" dependencies = [ "bytemuck", "openssl", - "solana-feature-set", "solana-instruction", - "solana-logger", - "solana-precompile-error", - "solana-sdk", "solana-sdk-ids", ] @@ -3759,16 +3806,16 @@ dependencies = [ [[package]] name = "solana-seed-phrase" -version = "2.2.1" +version = "3.0.0" dependencies = [ - "hmac 0.12.1", + "hmac", "pbkdf2 0.11.0", - "sha2 0.10.8", + "sha2", ] [[package]] name = "solana-serde" -version = "2.2.1" +version = "3.0.0" dependencies = [ "bincode", "serde", @@ -3780,7 +3827,7 @@ name = "solana-serde-varint" version = "2.2.2" dependencies = [ "bincode", - "rand 0.8.5", + "rand", "serde", "serde_derive", "solana-short-vec", @@ -3791,10 +3838,10 @@ name = "solana-serialize-utils" version = "2.2.1" dependencies = [ "bincode", - "borsh 1.5.5", - "rand 0.8.5", + "borsh", + "rand", "serde", - "solana-instruction", + "solana-instruction-error", "solana-pubkey", "solana-sanitize", ] @@ -3803,9 +3850,10 @@ dependencies = [ name = "solana-sha256-hasher" version = "2.2.1" dependencies = [ - "sha2 0.10.8", + "sha2", "solana-define-syscall", "solana-hash", + "solana-sha256-hasher", ] [[package]] @@ -3835,10 +3883,10 @@ version = "2.3.0" dependencies = [ "bincode", "bs58", - "curve25519-dalek 4.1.3", + "curve25519-dalek", "ed25519-dalek", "five8", - "rand 0.8.5", + "rand", "serde", "serde-big-array", "serde_derive", @@ -3860,6 +3908,17 @@ dependencies = [ "solana-transaction-error", ] +[[package]] +name = "solana-signer-store" +version = "0.1.0" +dependencies = [ + "bitvec", + "criterion", + "num-derive", + "num-traits", + "rand", +] + [[package]] name = "solana-slot-hashes" version = "2.2.1" @@ -3893,42 +3952,32 @@ dependencies = [ ] [[package]] -name = "solana-stake-interface" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +name = "solana-system-interface" +version = "1.0.0" dependencies = [ - "borsh 0.10.4", - "borsh 1.5.5", + "anyhow", + "borsh", "num-traits", "serde", "serde_derive", - "solana-clock", + "solana-account-info", "solana-cpi", - "solana-decode-error", + "solana-example-mocks", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-instruction", + "solana-logger", + "solana-msg", + "solana-nonce", + "solana-program-entrypoint", "solana-program-error", "solana-pubkey", "solana-system-interface", + "solana-sysvar", "solana-sysvar-id", -] - -[[package]] -name = "solana-system-interface" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" -dependencies = [ - "js-sys", - "num-traits", - "serde", - "serde_derive", - "solana-decode-error", - "solana-instruction", - "solana-pubkey", - "wasm-bindgen", + "static_assertions", + "strum", + "strum_macros", ] [[package]] @@ -3962,28 +4011,24 @@ dependencies = [ "solana-define-syscall", "solana-epoch-rewards", "solana-epoch-schedule", + "solana-example-mocks", "solana-fee-calculator", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-hash", "solana-instruction", - "solana-instructions-sysvar", "solana-last-restart-slot", "solana-msg", - "solana-program", "solana-program-entrypoint", "solana-program-error", "solana-program-memory", "solana-pubkey", "solana-rent", - "solana-sanitize", - "solana-sdk", "solana-sdk-ids", "solana-sdk-macro", "solana-sha256-hasher", "solana-slot-hashes", "solana-slot-history", - "solana-stake-interface", "solana-sysvar", "solana-sysvar-id", "test-case", @@ -3999,7 +4044,7 @@ dependencies = [ [[package]] name = "solana-time-utils" -version = "2.2.1" +version = "3.0.0" [[package]] name = "solana-transaction" @@ -4007,11 +4052,10 @@ version = "2.2.3" dependencies = [ "anyhow", "bincode", - "borsh 1.5.5", + "borsh", "serde", "serde_derive", - "solana-bincode", - "solana-feature-set", + "solana-example-mocks", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-hash", @@ -4021,11 +4065,9 @@ dependencies = [ "solana-message", "solana-nonce", "solana-packet", - "solana-precompiles", "solana-presigner", "solana-pubkey", "solana-sanitize", - "solana-sdk", "solana-sdk-ids", "solana-sha256-hasher", "solana-short-vec", @@ -4036,23 +4078,6 @@ dependencies = [ "solana-transaction-error", "solana-vote-interface", "static_assertions", - "wasm-bindgen", -] - -[[package]] -name = "solana-transaction-context" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5022de04cbba05377f68bf848c8c1322ead733f88a657bf792bb40f3257b8218" -dependencies = [ - "bincode", - "serde", - "serde_derive", - "solana-account", - "solana-instruction", - "solana-pubkey", - "solana-rent", - "solana-signature", ] [[package]] @@ -4063,13 +4088,13 @@ dependencies = [ "serde_derive", "solana-frozen-abi", "solana-frozen-abi-macro", - "solana-instruction", + "solana-instruction-error", "solana-sanitize", ] [[package]] name = "solana-validator-exit" -version = "2.2.1" +version = "3.0.0" [[package]] name = "solana-vote-interface" @@ -4080,16 +4105,16 @@ dependencies = [ "itertools 0.12.1", "num-derive", "num-traits", - "rand 0.8.5", + "rand", "serde", "serde_derive", "solana-clock", - "solana-decode-error", "solana-epoch-schedule", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-hash", "solana-instruction", + "solana-instruction-error", "solana-logger", "solana-pubkey", "solana-rent", @@ -4101,6 +4126,16 @@ dependencies = [ "solana-vote-interface", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -4205,12 +4240,22 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.4.1" +name = "tap" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "winapi-util", + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.59.0", ] [[package]] @@ -4257,11 +4302,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -4277,28 +4322,35 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", "syn 2.0.98", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "tiny-bip39" -version = "0.8.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +checksum = "a30fd743a02bf35236f6faf99adb03089bb77e91c998dac2c2ad76bb424f668c" dependencies = [ - "anyhow", - "hmac 0.8.1", "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", + "pbkdf2 0.12.2", + "rand", "rustc-hash", - "sha2 0.9.9", + "sha2", "thiserror 1.0.69", "unicode-normalization", "wasm-bindgen", @@ -4342,9 +4394,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.43.0" +version = "1.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "492a604e2fd7f814268a378409e6c92b5525d747d10db9a229723f55a417958c" dependencies = [ "backtrace", "bytes", @@ -4380,18 +4432,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.11" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -4401,26 +4444,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.23" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tower-service" version = "0.3.3" @@ -4518,6 +4568,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "vcpkg" version = "0.2.15" @@ -4551,15 +4607,18 @@ dependencies = [ [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] name = "wasm-bindgen" @@ -4658,37 +4717,15 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-sys" version = "0.48.0" @@ -4839,9 +4876,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.0" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e49d2d35d3fad69b39b94139037ecfb4f359f08958b9c11e7315ce770462419" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -4856,6 +4893,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -4868,6 +4914,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "yoke" version = "0.7.5" @@ -4936,9 +4991,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.3.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] diff --git a/Cargo.toml b/Cargo.toml index e4bccc3d9..da121a68b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,13 @@ members = [ "account", "account-info", + "address", "address-lookup-table-interface", "atomic-u64", "big-mod-exp", "bincode", "blake3-hasher", + "bls-signatures", "bn254", "borsh", "client-traits", @@ -15,7 +17,6 @@ members = [ "commitment-config", "compute-budget-interface", "cpi", - "decode-error", "define-syscall", "derivation-path", "ed25519-program", @@ -23,10 +24,9 @@ members = [ "epoch-rewards", "epoch-rewards-hasher", "epoch-schedule", + "epoch-stake", "example-mocks", "feature-gate-interface", - "feature-set", - "feature-set-interface", "fee-calculator", "fee-structure", "file-download", @@ -37,6 +37,7 @@ members = [ "hash", "inflation", "instruction", + "instruction-error", "instructions-sysvar", "keccak-hasher", "keypair", @@ -55,7 +56,6 @@ members = [ "packet", "poh-config", "precompile-error", - "precompiles", "presigner", "program", "program-entrypoint", @@ -67,13 +67,13 @@ members = [ "quic-definitions", "rent", "rent-collector", - "rent-debits", - "reserved-account-keys", "reward-info", "sanitize", "sdk", "sdk-ids", "sdk-macro", + "sdk-wasm-js", + "sdk-wasm-js-tests", "secp256k1-program", "secp256k1-recover", "secp256r1-program", @@ -87,6 +87,7 @@ members = [ "shred-version", "signature", "signer", + "signer-store", "slot-hashes", "slot-history", "stable-layout", @@ -122,7 +123,7 @@ tag-message = "Publish {{crate_name}} v{{version}}" consolidate-commits = false [workspace.metadata.cli] -solana = "2.2.7" +solana = "2.2.11" [workspace.dependencies] ahash = "0.8.11" @@ -132,14 +133,17 @@ ark-bn254 = "0.4.0" ark-ec = "0.4.0" ark-ff = "0.4.0" ark-serialize = "0.4.0" -array-bytes = "=1.4.1" +array-bytes = "1.4.1" assert_matches = "1.5.0" base64 = "0.22.1" bincode = "1.3.3" bitflags = { version = "2.8.0" } +bitvec = "1.0.1" blake3 = "1.5.5" +blst = "0.3.14" +blstrs = "0.7.1" borsh = { version = "1.5.5", features = ["derive", "unstable__schema"] } -borsh0-10 = { package = "borsh", version = "0.10.3" } +boxcar = "0.2.12" bs58 = { version = "0.5.1", default-features = false } bv = "0.11.1" bytemuck = "1.21.0" @@ -152,26 +156,26 @@ console_error_panic_hook = "0.1.7" console_log = "0.2.2" criterion = "0.5.1" curve25519-dalek = { version = "4.1.3", features = ["digest", "rand_core"] } +dashmap = { version = "5.5.3", features = ["serde"] } derivation-path = { version = "0.2.0", default-features = false } digest = "0.10.7" -ed25519-dalek = "=1.0.1" -ed25519-dalek-bip32 = "0.2.0" -env_logger = "0.9.3" +ed25519-dalek = "2.1.1" +ed25519-dalek-bip32 = "0.3.0" +env_logger = "0.11.0" +ff = "0.13.1" five8 = "0.2.1" five8_const = "0.1.3" getrandom = "0.2.10" +group = "0.13.0" hex = "0.4.3" hmac = "0.12.1" im = "15.1.0" indicatif = "0.17.9" itertools = "0.12.1" js-sys = "0.3.77" +k256 = "0.13.0" lazy_static = "1.5.0" libc = "0.2.170" -libsecp256k1 = { version = "0.6.0", default-features = false, features = [ - "std", - "static-context", -] } log = "0.4.25" memmap2 = "0.5.10" memoffset = "0.9" @@ -180,6 +184,7 @@ num-derive = "0.4" num-traits = "0.2.18" num_enum = "0.7.3" openssl = "0.10.72" +pairing = "0.23.0" parking_lot = "0.12" pbkdf2 = { version = "0.11.0", default-features = false } proc-macro2 = "1.0.93" @@ -188,7 +193,7 @@ qstring = "0.7.2" qualifier_attr = { version = "0.2.2", default-features = false } quote = "1.0.35" rand = "0.8.5" -rand0-7 = { package = "rand", version = "0.7" } +rayon = "1.10.0" reqwest = { version = "0.11.27", default-features = false } serde = "1.0.217" # must match the serde_derive version, see https://github.com/serde-rs/serde/issues/2584#issuecomment-1685252251 serde-big-array = "0.5.1" @@ -203,41 +208,42 @@ signal-hook = "0.3.17" siphasher = "0.3.11" solana-account = { path = "account", version = "2.2.1" } solana-account-info = { path = "account-info", version = "2.2.1" } +solana-address = { path = "address", version = "0.1.0" } solana-address-lookup-table-interface = { path = "address-lookup-table-interface", version = "2.2.2" } -solana-atomic-u64 = { path = "atomic-u64", version = "2.2.1" } +solana-atomic-u64 = { path = "atomic-u64", version = "3.0.0" } solana-big-mod-exp = { path = "big-mod-exp", version = "2.2.1" } solana-bincode = { path = "bincode", version = "2.2.1" } solana-blake3-hasher = { path = "blake3-hasher", version = "2.2.1" } +solana-bls-signatures = { path = "bls-signatures", version = "0.1.1" } solana-bn254 = { path = "bn254", version = "2.2.2" } -solana-borsh = { path = "borsh", version = "2.2.1" } +solana-borsh = { path = "borsh", version = "3.0.0" } solana-client-traits = { path = "client-traits", version = "2.2.1" } solana-clock = { path = "clock", version = "2.2.1" } solana-cluster-type = { path = "cluster-type", version = "2.2.1" } -solana-commitment-config = { path = "commitment-config", version = "2.2.1" } +solana-commitment-config = { path = "commitment-config", version = "3.0.0" } solana-compute-budget-interface = { path = "compute-budget-interface", version = "2.2.1" } solana-cpi = { path = "cpi", version = "2.2.1" } -solana-decode-error = { path = "decode-error", version = "2.2.1" } -solana-define-syscall = { path = "define-syscall", version = "2.2.1" } -solana-derivation-path = { path = "derivation-path", version = "2.2.1" } +solana-define-syscall = { path = "define-syscall", version = "3.0.0" } +solana-derivation-path = { path = "derivation-path", version = "3.0.0" } solana-ed25519-program = { path = "ed25519-program", version = "2.2.1" } -solana-epoch-info = { path = "epoch-info", version = "2.2.1" } +solana-epoch-info = { path = "epoch-info", version = "3.0.0" } solana-epoch-rewards = { path = "epoch-rewards", version = "2.2.1" } solana-epoch-rewards-hasher = { path = "epoch-rewards-hasher", version = "2.2.1" } solana-epoch-schedule = { path = "epoch-schedule", version = "2.2.1" } +solana-epoch-stake = { path = "epoch-stake", version = "2.2.1" } solana-example-mocks = { path = "example-mocks", version = "2.2.1" } solana-feature-gate-interface = { path = "feature-gate-interface", version = "2.2.1" } -solana-feature-set = { path = "feature-set", version = "2.2.1" } -solana-feature-set-interface = { path = "feature-set-interface", version = "4.0.1" } solana-fee-calculator = { path = "fee-calculator", version = "2.2.1" } solana-fee-structure = { path = "fee-structure", version = "2.2.1" } -solana-file-download = { path = "file-download", version = "2.2.1" } -solana-frozen-abi = { path = "frozen-abi", version = "2.2.1" } -solana-frozen-abi-macro = { path = "frozen-abi-macro", version = "2.2.1" } +solana-file-download = { path = "file-download", version = "3.0.0" } +solana-frozen-abi = { path = "frozen-abi", version = "3.0.0" } +solana-frozen-abi-macro = { path = "frozen-abi-macro", version = "3.0.0" } solana-genesis-config = { path = "genesis-config", version = "2.2.1" } solana-hard-forks = { path = "hard-forks", version = "2.2.1", default-features = false } solana-hash = { path = "hash", version = "2.2.1", default-features = false } solana-inflation = { path = "inflation", version = "2.2.1" } solana-instruction = { path = "instruction", version = "2.3.0", default-features = false } +solana-instruction-error = { path = "instruction-error", version = "1.0.0" } solana-instructions-sysvar = { path = "instructions-sysvar", version = "2.2.1" } solana-keccak-hasher = { path = "keccak-hasher", version = "2.2.1" } solana-keypair = { path = "keypair", version = "2.2.1" } @@ -245,43 +251,41 @@ solana-last-restart-slot = { path = "last-restart-slot", version = "2.2.1" } solana-loader-v2-interface = { path = "loader-v2-interface", version = "2.2.1" } solana-loader-v3-interface = { path = "loader-v3-interface", version = "5.0.0" } solana-loader-v4-interface = { path = "loader-v4-interface", version = "2.2.1" } -solana-logger = { path = "logger", version = "2.2.1" } +solana-logger = { path = "logger", version = "3.0.0" } solana-message = { path = "message", version = "2.2.1" } -solana-msg = { path = "msg", version = "2.2.1" } -solana-native-token = { path = "native-token", version = "2.2.1" } +solana-msg = { path = "msg", version = "3.0.0" } +solana-native-token = { path = "native-token", version = "3.0.0" } solana-nonce = { path = "nonce", version = "2.2.1" } solana-nonce-account = { path = "nonce-account", version = "2.2.1" } solana-offchain-message = { path = "offchain-message", version = "2.2.1" } solana-package-metadata = { path = "package-metadata", version = "2.2.1" } -solana-package-metadata-macro = { path = "package-metadata-macro", version = "2.2.1" } +solana-package-metadata-macro = { path = "package-metadata-macro", version = "3.0.0" } solana-packet = { path = "packet", version = "2.2.1" } solana-poh-config = { path = "poh-config", version = "2.2.1" } -solana-precompile-error = { path = "precompile-error", version = "2.2.1" } -solana-precompiles = { path = "precompiles", version = "2.2.1" } +solana-precompile-error = { path = "precompile-error", version = "3.0.0" } solana-presigner = { path = "presigner", version = "2.2.1" } solana-program = { path = "program", version = "2.2.1", default-features = false } solana-program-entrypoint = { path = "program-entrypoint", version = "2.2.1" } -solana-program-error = { path = "program-error", version = "2.2.1" } -solana-program-memory = { path = "program-memory", version = "2.2.1" } -solana-program-option = { path = "program-option", version = "2.2.1" } +solana-program-error = { path = "program-error", version = "3.0.0" } +solana-program-memory = { path = "program-memory", version = "3.0.0" } +solana-program-option = { path = "program-option", version = "3.0.0" } solana-program-pack = { path = "program-pack", version = "2.2.1" } solana-pubkey = { path = "pubkey", version = "2.2.1", default-features = false } solana-quic-definitions = { path = "quic-definitions", version = "2.2.1" } solana-rent = { path = "rent", version = "2.2.1", default-features = false } solana-rent-collector = { path = "rent-collector", version = "2.2.1" } -solana-rent-debits = { path = "rent-debits", version = "2.2.1" } -solana-reserved-account-keys = { path = "reserved-account-keys", version = "2.2.1", default-features = false } solana-reward-info = { path = "reward-info", version = "2.2.1" } -solana-sanitize = { path = "sanitize", version = "2.2.1" } +solana-sanitize = { path = "sanitize", version = "3.0.0" } solana-sdk = { path = "sdk", version = "2.2.1" } solana-sdk-ids = { path = "sdk-ids", version = "2.2.1" } -solana-sdk-macro = { path = "sdk-macro", version = "2.2.1" } +solana-sdk-macro = { path = "sdk-macro", version = "3.0.0" } +solana-sdk-wasm-js = { path = "sdk-wasm-js", version = "1.0.0" } solana-secp256k1-program = { path = "secp256k1-program", version = "2.2.1" } solana-secp256k1-recover = { path = "secp256k1-recover", version = "2.2.1" } solana-secp256r1-program = { path = "secp256r1-program", version = "2.2.1", default-features = false } solana-seed-derivable = { path = "seed-derivable", version = "2.2.1" } -solana-seed-phrase = { path = "seed-phrase", version = "2.2.1" } -solana-serde = { path = "serde", version = "2.2.1" } +solana-seed-phrase = { path = "seed-phrase", version = "3.0.0" } +solana-serde = { path = "serde", version = "3.0.0" } solana-serde-varint = { path = "serde-varint", version = "2.2.1" } solana-serialize-utils = { path = "serialize-utils", version = "2.2.1" } solana-sha256-hasher = { path = "sha256-hasher", version = "2.2.1" } @@ -289,28 +293,29 @@ solana-short-vec = { path = "short-vec", version = "2.2.1" } solana-shred-version = { path = "shred-version", version = "2.2.1" } solana-signature = { path = "signature", version = "2.3.0", default-features = false } solana-signer = { path = "signer", version = "2.2.1" } +solana-signer-store = { path = "signer-store", version = "0.1.0" } solana-slot-hashes = { path = "slot-hashes", version = "2.2.1" } solana-slot-history = { path = "slot-history", version = "2.2.1" } solana-stable-layout = { path = "stable-layout", version = "2.2.1" } -solana-stake-interface = { version = "1.2.1" } -solana-system-interface = "1.0" +solana-system-interface = { path = "system-interface", version = "1.0" } solana-system-transaction = { path = "system-transaction", version = "2.2.1" } solana-sysvar = { path = "sysvar", version = "2.2.1" } solana-sysvar-id = { path = "sysvar-id", version = "2.2.1" } -solana-time-utils = { path = "time-utils", version = "2.2.1" } +solana-time-utils = { path = "time-utils", version = "3.0.0" } solana-transaction = { path = "transaction", version = "2.2.1" } -solana-transaction-context = { version = "2.2.1" } solana-transaction-error = { path = "transaction-error", version = "2.2.1" } -solana-validator-exit = { path = "validator-exit", version = "2.2.1" } +solana-validator-exit = { path = "validator-exit", version = "3.0.0" } solana-vote-interface = { path = "vote-interface", version = "2.2.1" } static_assertions = "1.1.0" strum = "0.24" strum_macros = "0.24" +subtle = "2.6.1" syn = "2.0.87" +tempfile = "3.20.0" test-case = "3.3.1" thiserror = "2.0.11" -tiny-bip39 = "0.8.2" -toml = "0.8.20" +tiny-bip39 = "2.0.0" +toml = "0.8.23" uriparse = "0.6.4" wasm-bindgen = "0.2.100" @@ -325,39 +330,3 @@ opt-level = 1 # Enable optimizations for procmacros for faster recompile [profile.dev.build-override] opt-level = 1 - -[patch.crates-io] -# We include the following crates as our dependencies above from crates.io: -# -# * solana-system-interface -# -# They, in turn, depend on a number of crates that we also include directly -# using `path` specifications. For example, `solana-system-interface` depends -# on `solana-instruction`. And we explicitly specify `solana-instruction` above -# as a local path dependency: -# -# solana-instruction = { path = "instruction", version = "2.2.1" } -# -# Unfortunately, Cargo will try to resolve the `solana-system-interface` -# `solana-instruction` dependency only using what is available on crates.io. -# Crates.io normally contains a previous version of these crates, and we end up -# with two versions of `solana-instruction` and all of their dependencies in our -# build tree. -# -# If you are developing downstream using non-crates-io solana-program (local or -# forked repo, or from github rev, eg), duplicate the following patch statements -# in your Cargo.toml. If you still hit duplicate-type errors with the patch -# statements in place, run `cargo update -p solana-program` to remove extraneous -# versions from your Cargo.lock file. -solana-account = { path = "account" } -solana-clock = { path = "clock" } -solana-cpi = { path = "cpi" } -solana-decode-error = { path = "decode-error" } -solana-frozen-abi = { path = "frozen-abi" } -solana-frozen-abi-macro = { path = "frozen-abi-macro" } -solana-instruction = { path = "instruction" } -solana-program-error = { path = "program-error" } -solana-pubkey = { path = "pubkey" } -solana-rent = { path = "rent" } -solana-signature = { path = "signature" } -solana-sysvar-id = { path = "sysvar-id" } diff --git a/README.md b/README.md index cc2a22a49..90ab3ca42 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,77 @@ Rust SDK for the Solana blockchain, used by on-chain programs and the Agave validator. +## Upgrading from v2 to v3 + +### solana-sdk + +The following modules have been removed, please use their component crates +directly: + +* [`address_lookup_table`](https://docs.rs/solana-sdk/latest/solana_sdk/address_lookup_table) -> [`solana_address_lookup_table_interface`](https://docs.rs/solana-address-lookup-table-interface/latest/solana_address_lookup_table_interface/) +* [`alt_bn128`](https://docs.rs/solana-sdk/latest/solana_sdk/alt_bn128) -> [`solana_bn254`](https://docs.rs/solana-bn254/latest/solana_bn254) +* [`bpf_loader_upgradeable`](https://docs.rs/solana-sdk/latest/solana_sdk/bpf_loader_upgradeable) -> [`solana_loader_v3_interface`](https://docs.rs/solana-loader-v3-interface/latest/solana_loader_v3_interface) +* [`client`](https://docs.rs/solana-sdk/latest/solana_sdk/client) -> [`solana_client_traits`](https://docs.rs/solana-client-traits/latest/solana_client_traits) +* [`commitment_config`](https://docs.rs/solana-sdk/latest/solana_sdk/commitment_config) -> [`solana_commitment_config`](https://docs.rs/solana-commitment-config/latest/solana_commitment_config) +* [`compute_budget`](https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget) -> [`solana_compute_budget_interface`](https://docs.rs/solana-compute-budget-interface/latest/solana_compute_budget_interface) +* [`decode_error`](https://docs.rs/solana-sdk/latest/solana_sdk/decode_error) -> [`solana_decode_error`](https://docs.rs/solana-decode-error/latest/solana_decode_error) +* [`derivation_path`](https://docs.rs/solana-sdk/latest/solana_sdk/derivation_path) -> [`solana_derivation_path`](https://docs.rs/solana-derivation-path/latest/solana_derivation_path) +* [`ed25519_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/ed25519_instruction) -> [`solana_ed25519_program`](https://docs.rs/solana-ed25519-program/latest/solana_ed25519_program) +* [`exit`](https://docs.rs/solana-sdk/latest/solana_sdk/exit) -> [`solana_validator_exit`](https://docs.rs/solana-validator-exit/latest/solana_validator_exit) +* [`feature_set`](https://docs.rs/solana-sdk/latest/solana_sdk/feature_set) -> [`agave_feature_set`](https://docs.rs/agave-feature-set/latest/agave_feature_set) +* [`feature`](https://docs.rs/solana-sdk/latest/solana_sdk/feature) -> [`solana_feature_gate_interface`](https://docs.rs/solana-feature-gate-interface/latest/solana_feature_gate_interface) +* [`genesis_config`](https://docs.rs/solana-sdk/latest/solana_sdk/genesis_config) -> [`solana_genesis_config`](https://docs.rs/solana-genesis-config/latest/solana_genesis_config) +* [`hard_forks`](https://docs.rs/solana-sdk/latest/solana_sdk/hard_forks) -> [`solana_hard_forks`](https://docs.rs/solana-hard-forks/latest/solana_hard_forks) +* [`loader_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/loader_instruction) -> [`solana_loader_v2_interface`](https://docs.rs/solana-loader-v2-interface/latest/solana_loader_v2_interface) +* [`loader_upgradeable_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/loader_upgradeable_instruction) -> [`solana_loader_v3_interface::instruction`](https://docs.rs/solana-loader-v3-interface/latest/solana_loader_v3_interface/instruction) +* [`loader_v4`](https://docs.rs/solana-sdk/latest/solana_sdk/loader_v4) -> [`solana_loader_v4_interface`](https://docs.rs/solana-loader-v4-interface/latest/solana_loader_v4_interface) +* [`loader_v4_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/loader_v4_instruction) -> [`solana_loader_v4_interface::instruction`](https://docs.rs/solana-loader-v4-interface/latest/solana_loader_v4_interface/instruction) +* [`nonce`](https://docs.rs/solana-sdk/latest/solana_sdk/nonce) -> [`solana_nonce`](https://docs.rs/solana-nonce/latest/solana_nonce) +* [`nonce_account`](https://docs.rs/solana-sdk/latest/solana_sdk/nonce_account) -> [`solana_nonce_account`](https://docs.rs/solana-nonce-account/latest/solana_nonce_account) +* [`packet`](https://docs.rs/solana-sdk/latest/solana_sdk/packet) -> [`solana_packet`](https://docs.rs/solana-packet/latest/solana_packet) +* [`poh_config`](https://docs.rs/solana-sdk/latest/solana_sdk/poh_config) -> [`solana_poh_config`](https://docs.rs/solana-poh-config/latest/solana_poh_config) +* [`precompiles`](https://docs.rs/solana-sdk/latest/solana_sdk/precompiles) -> [`agave_precompiles`](https://docs.rs/agave-precompiles/latest/agave_precompiles) +* [`program_utils`](https://docs.rs/solana-sdk/latest/solana_sdk/program_utils) -> [`solana_bincode::limited_deserialize`](https://docs.rs/solana-bincode/latest/solana_bincode) +* [`quic`](https://docs.rs/solana-sdk/latest/solana_sdk/quic) -> [`solana_quic_definitions`](https://docs.rs/solana-quic-definitions/latest/solana_quic_definitions) +* [`rent_collector`](https://docs.rs/solana-sdk/latest/solana_sdk/rent_collector) -> [`solana_rent_collector`](https://docs.rs/solana-rent-collector/latest/solana_rent_collector) +* [`reserved_account_keys`](https://docs.rs/solana-sdk/latest/solana_sdk/reserved_account_keys) -> [`agave_reserved_account_keys`](https://docs.rs/agave-reserved-account-keys/latest/agave_reserved_account_keys) +* [`reward_info`](https://docs.rs/solana-sdk/latest/solana_sdk/reward_info) -> [`solana_reward_info`](https://docs.rs/solana-reward-info/latest/solana_reward_info) +* [`reward_type`](https://docs.rs/solana-sdk/latest/solana_sdk/reward_type) -> [`solana_reward_info`](https://docs.rs/solana-reward-info/latest/solana_reward_info) +* [`sdk_ids`](https://docs.rs/solana-sdk/latest/solana_sdk/sdk_ids) -> [`solana_sdk_ids`](https://docs.rs/solana-sdk-ids/latest/solana_sdk_ids) +* [`secp256k1_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/secp256k1_instruction) -> [`solana_secp256k1_program`](https://docs.rs/solana-secp256k1-program/latest/solana_secp256k1_program) +* [`secp256k1_recover`](https://docs.rs/solana-sdk/latest/solana_sdk/secp256k1_recover) -> [`solana_secp256k1_recover`](https://docs.rs/solana-secp256k1-recover/latest/solana_secp256k1_recover) +* [`stake`](https://docs.rs/solana-sdk/latest/solana_sdk/stake) -> [`solana_stake_interface`](https://docs.rs/solana-stake-interface/latest/solana_stake_interface) +* [`stake_history`](https://docs.rs/solana-sdk/latest/solana_sdk/stake_history) -> [`solana_stake_interface::stake_history`](https://docs.rs/solana-stake-interface/latest/solana_stake_interface/stake_history) +* [`system_instruction`](https://docs.rs/solana-sdk/latest/solana_sdk/system_instruction) -> [`solana_system_interface::instruction`](https://docs.rs/solana-system-interface/latest/solana_system_interface/instruction) +* [`system_program`](https://docs.rs/solana-sdk/latest/solana_sdk/system_program) -> [`solana_system_interface::program`](https://docs.rs/solana-system-interface/latest/solana_system_interface/program) +* [`system_transaction`](https://docs.rs/solana-sdk/latest/solana_sdk/system_transaction) -> [`solana_system_transaction`](https://docs.rs/solana-system-transaction/latest/solana_system_transaction) +* [`transaction_context`](https://docs.rs/solana-sdk/latest/solana_sdk/transaction_context) -> [`solana_transaction_context`](https://docs.rs/solana-transaction-context/latest/solana_transaction_context) +* [`vote`](https://docs.rs/solana-sdk/latest/solana_sdk/vote) -> [`solana_vote_interface`](https://docs.rs/solana-vote-interface/latest/solana_vote_interface) + +### solana-program + +The following modules have been removed, please use their component crates +directly: + +* [`address_lookup_table`](https://docs.rs/solana-program/latest/solana_program/address_lookup_table) -> [`solana_address_lookup_table_interface`](https://docs.rs/solana-address-lookup-table-interface/latest/solana_address_lookup_table_interface/) +* [`bpf_loader_upgradeable`](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable) -> [`solana_loader_v3_interface`](https://docs.rs/solana-loader-v3-interface/latest/solana_loader_v3_interface) +* [`decode_error`](https://docs.rs/solana-program/latest/solana_program/decode_error) -> [`solana_decode_error`](https://docs.rs/solana-decode-error/latest/solana_decode_error) +* [`feature`](https://docs.rs/solana-program/latest/solana_program/feature) -> [`solana_feature_gate_interface`](https://docs.rs/solana-feature-gate-interface/latest/solana_feature_gate_interface) +* [`loader_instruction`](https://docs.rs/solana-program/latest/solana_program/loader_instruction) -> [`solana_loader_v2_interface`](https://docs.rs/solana-loader-v2-interface/latest/solana_loader_v2_interface) +* [`loader_upgradeable_instruction`](https://docs.rs/solana-program/latest/solana_program/loader_upgradeable_instruction) -> [`solana_loader_v3_interface::instruction`](https://docs.rs/solana-loader-v3-interface/latest/solana_loader_v3_interface/instruction) +* [`loader_v4`](https://docs.rs/solana-program/latest/solana_program/loader_v4) -> [`solana_loader_v4_interface`](https://docs.rs/solana-loader-v4-interface/latest/solana_loader_v4_interface) +* [`loader_v4_instruction`](https://docs.rs/solana-program/latest/solana_program/loader_v4_instruction) -> [`solana_loader_v4_interface::instruction`](https://docs.rs/solana-loader-v4-interface/latest/solana_loader_v4_interface/instruction) +* [`message`](https://docs.rs/solana-program/latest/solana_program/message) -> [`solana_message`](https://docs.rs/solana-message/latest/solana_message) +* [`nonce`](https://docs.rs/solana-program/latest/solana_program/nonce) -> [`solana_nonce`](https://docs.rs/solana-nonce/latest/solana_nonce) +* [`program_utils`](https://docs.rs/solana-program/latest/solana_program/program_utils) -> [`solana_bincode::limited_deserialize`](https://docs.rs/solana-bincode/latest/solana_bincode) +* [`sanitize`](https://docs.rs/solana-program/latest/solana_program/sanitize) -> [`solana_sanitize`](https://docs.rs/solana-sanitize/latest/solana_sanitize) +* [`sdk_ids`](https://docs.rs/solana-program/latest/solana_program/sdk_ids) -> [`solana_sdk_ids`](https://docs.rs/solana-sdk-ids/latest/solana_sdk_ids) +* [`stake`](https://docs.rs/solana-program/latest/solana_program/stake) -> [`solana_stake_interface`](https://docs.rs/solana-stake-interface/latest/solana_stake_interface) +* [`stake_history`](https://docs.rs/solana-program/latest/solana_program/stake_history) -> [`solana_stake_interface::stake_history`](https://docs.rs/solana-stake-interface/latest/solana_stake_interface/stake_history) +* [`system_instruction`](https://docs.rs/solana-program/latest/solana_program/system_instruction) -> [`solana_system_interface::instruction`](https://docs.rs/solana-system-interface/latest/solana_system_interface/instruction) +* [`system_program`](https://docs.rs/solana-program/latest/solana_program/system_program) -> [`solana_system_interface::program`](https://docs.rs/solana-system-interface/latest/solana_system_interface/program) +* [`vote`](https://docs.rs/solana-program/latest/solana_program/vote) -> [`solana_vote_interface`](https://docs.rs/solana-vote-interface/latest/solana_vote_interface) + ## Building ### **1. Install rustc, cargo and rustfmt.** @@ -53,6 +124,9 @@ To patch all of the crates in this repo for Agave, just run: ### Publishing a crate from this repository +NOTE: The repo currently contains unpublished breaking changes, so please +double-check before publishing any crates! + Unlike Agave, the solana-sdk crates are versioned independently, and published as needed. @@ -65,6 +139,14 @@ The publish job will run checks, bump the crate version, commit and tag the bump, publish the crate to crates.io, and finally create GitHub Release with a simple changelog of all commits to the crate since the previous release. +### Backports + +If you would like to backport a pull request, simply add the appropriate label, +named `backport `. + +For example, to create a backport to the `maintenance/v2.x` branch, just add the +`backport maintenance/v2.x` label. + ## Testing Certain tests, such as `rustfmt` and `clippy`, require the nightly rustc diff --git a/account-info/src/lib.rs b/account-info/src/lib.rs index febd4aedc..9ccc05feb 100644 --- a/account-info/src/lib.rs +++ b/account-info/src/lib.rs @@ -28,8 +28,14 @@ pub struct AccountInfo<'a> { pub data: Rc>, /// Program that owns this account pub owner: &'a Pubkey, - /// The epoch at which this account will next owe rent - pub rent_epoch: u64, + /// Formerly, the epoch at which this account will next owe rent. A field + /// must remain because the runtime depends on the exact layout of this + /// struct. + #[deprecated( + since = "3.0.0", + note = "Do not use this field, it will not exist in ABIv2" + )] + pub _unused: u64, /// Was the transaction signed by this account's public key? pub is_signer: bool, /// Is the account writable? @@ -47,7 +53,6 @@ impl fmt::Debug for AccountInfo<'_> { .field("is_signer", &self.is_signer) .field("is_writable", &self.is_writable) .field("executable", &self.executable) - .field("rent_epoch", &self.rent_epoch) .field("lamports", &self.lamports()) .field("data.len", &self.data_len()); debug_account_data::debug_account_data(&self.data.borrow(), &mut f); @@ -106,47 +111,42 @@ impl<'a> AccountInfo<'a> { Ok(self.try_borrow_data()?.is_empty()) } - pub fn try_borrow_lamports(&self) -> Result, ProgramError> { + pub fn try_borrow_lamports(&self) -> Result, ProgramError> { self.lamports .try_borrow() .map_err(|_| ProgramError::AccountBorrowFailed) } - pub fn try_borrow_mut_lamports(&self) -> Result, ProgramError> { + pub fn try_borrow_mut_lamports(&self) -> Result, ProgramError> { self.lamports .try_borrow_mut() .map_err(|_| ProgramError::AccountBorrowFailed) } - pub fn try_borrow_data(&self) -> Result, ProgramError> { + pub fn try_borrow_data(&self) -> Result, ProgramError> { self.data .try_borrow() .map_err(|_| ProgramError::AccountBorrowFailed) } - pub fn try_borrow_mut_data(&self) -> Result, ProgramError> { + pub fn try_borrow_mut_data(&self) -> Result, ProgramError> { self.data .try_borrow_mut() .map_err(|_| ProgramError::AccountBorrowFailed) } - /// Realloc the account's data and optionally zero-initialize the new - /// memory. + /// Resize the account's data: Either truncating or zero extending. /// /// Note: Account data can be increased within a single call by up to /// `solana_program::entrypoint::MAX_PERMITTED_DATA_INCREASE` bytes. /// - /// Note: `zero_init` being `false` will no longer be supported by the - /// program runtime. - /// /// # Safety /// /// This method makes assumptions about the layout and location of memory /// referenced by `AccountInfo` fields. It should only be called for /// instances of `AccountInfo` that were created by the runtime and received /// in the `process_instruction` entrypoint of a program. - #[deprecated(since = "2.3.0", note = "Use AccountInfo::resize() instead")] - pub fn realloc(&self, new_len: usize, zero_init: bool) -> Result<(), ProgramError> { + pub fn resize(&self, new_len: usize) -> Result<(), ProgramError> { let mut data = self.try_borrow_mut_data()?; let old_len = data.len(); @@ -173,32 +173,14 @@ impl<'a> AccountInfo<'a> { *data = from_raw_parts_mut(data_ptr, new_len) } - if zero_init { - let len_increase = new_len.saturating_sub(old_len); - if len_increase > 0 { - sol_memset(&mut data[old_len..], 0, len_increase); - } + let len_increase = new_len.saturating_sub(old_len); + if len_increase > 0 { + unsafe { sol_memset(&mut data[old_len..], 0, len_increase) }; } Ok(()) } - /// Resize the account's data: Either truncating or zero extending. - /// - /// Note: Account data can be increased within a single call by up to - /// `solana_program::entrypoint::MAX_PERMITTED_DATA_INCREASE` bytes. - /// - /// # Safety - /// - /// This method makes assumptions about the layout and location of memory - /// referenced by `AccountInfo` fields. It should only be called for - /// instances of `AccountInfo` that were created by the runtime and received - /// in the `process_instruction` entrypoint of a program. - pub fn resize(&self, new_len: usize) -> Result<(), ProgramError> { - #[allow(deprecated)] - self.realloc(new_len, true) - } - #[allow(invalid_reference_casting)] pub fn assign(&self, new_owner: &Pubkey) { // Set the non-mut owner field @@ -218,8 +200,8 @@ impl<'a> AccountInfo<'a> { data: &'a mut [u8], owner: &'a Pubkey, executable: bool, - rent_epoch: u64, ) -> Self { + #[allow(deprecated)] Self { key, is_signer, @@ -228,7 +210,7 @@ impl<'a> AccountInfo<'a> { data: Rc::new(RefCell::new(data)), owner, executable, - rent_epoch, + _unused: 0, } } @@ -259,17 +241,15 @@ impl<'a, T: IntoAccountInfo<'a>> From for AccountInfo<'a> { /// Provides information required to construct an `AccountInfo`, used in /// conversion implementations. pub trait Account { - fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, u64); + fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool); } /// Convert (&'a Pubkey, &'a mut T) where T: Account into an `AccountInfo` impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, &'a mut T) { fn into_account_info(self) -> AccountInfo<'a> { let (key, account) = self; - let (lamports, data, owner, executable, rent_epoch) = account.get(); - AccountInfo::new( - key, false, false, lamports, data, owner, executable, rent_epoch, - ) + let (lamports, data, owner, executable) = account.get(); + AccountInfo::new(key, false, false, lamports, data, owner, executable) } } @@ -278,10 +258,8 @@ impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, &'a mut T) { impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, bool, &'a mut T) { fn into_account_info(self) -> AccountInfo<'a> { let (key, is_signer, account) = self; - let (lamports, data, owner, executable, rent_epoch) = account.get(); - AccountInfo::new( - key, is_signer, false, lamports, data, owner, executable, rent_epoch, - ) + let (lamports, data, owner, executable) = account.get(); + AccountInfo::new(key, is_signer, false, lamports, data, owner, executable) } } @@ -289,10 +267,8 @@ impl<'a, T: Account> IntoAccountInfo<'a> for (&'a Pubkey, bool, &'a mut T) { impl<'a, T: Account> IntoAccountInfo<'a> for &'a mut (Pubkey, T) { fn into_account_info(self) -> AccountInfo<'a> { let (ref key, account) = self; - let (lamports, data, owner, executable, rent_epoch) = account.get(); - AccountInfo::new( - key, false, false, lamports, data, owner, executable, rent_epoch, - ) + let (lamports, data, owner, executable) = account.get(); + AccountInfo::new(key, false, false, lamports, data, owner, executable) } } @@ -331,7 +307,7 @@ impl<'a, T: Account> IntoAccountInfo<'a> for &'a mut (Pubkey, T) { /// # let p = Pubkey::new_unique(); /// # let l = &mut 0; /// # let d = &mut [0u8]; -/// # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0); +/// # let a = AccountInfo::new(&p, false, false, l, d, &p, false); /// # let accounts = &[a.clone(), a]; /// # process_instruction( /// # &Pubkey::new_unique(), @@ -381,7 +357,7 @@ pub fn next_account_info<'a, 'b, I: Iterator>>( /// # let p = Pubkey::new_unique(); /// # let l = &mut 0; /// # let d = &mut [0u8]; -/// # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0); +/// # let a = AccountInfo::new(&p, false, false, l, d, &p, false); /// # let accounts = &[a.clone(), a.clone(), a.clone(), a.clone(), a]; /// # process_instruction( /// # &Pubkey::new_unique(), @@ -409,6 +385,78 @@ impl<'a> AsRef> for AccountInfo<'a> { } } +#[doc(hidden)] +#[allow(clippy::arithmetic_side_effects)] +pub fn check_type_assumptions() { + use std::mem::offset_of; + + let key = Pubkey::new_from_array([10; 32]); + let mut lamports = 31; + let mut data = vec![1, 2, 3, 4, 5]; + let owner = Pubkey::new_from_array([22; 32]); + let account_info = AccountInfo::new(&key, true, false, &mut lamports, &mut data, &owner, true); + let account_info_addr = &account_info as *const _ as u64; + + // key + assert_eq!(offset_of!(AccountInfo, key), 0); + let key_ptr = (account_info_addr) as *const &Pubkey; + unsafe { + assert_eq!(**key_ptr, key); + } + + // lamports + assert_eq!(offset_of!(AccountInfo, lamports), 8); + let lamports_ptr = (account_info_addr + 8) as *const Rc>; + unsafe { + assert_eq!(**(*lamports_ptr).as_ptr(), 31); + } + + // data + assert_eq!(offset_of!(AccountInfo, data), 16); + let data_ptr = (account_info_addr + 16) as *const Rc>; + unsafe { + assert_eq!((&(*(*data_ptr).as_ptr()))[..], data[..]); + } + + // owner + assert_eq!(offset_of!(AccountInfo, owner), 24); + let owner_ptr = (account_info_addr + 24) as *const &Pubkey; + unsafe { + assert_eq!(**owner_ptr, owner); + } + + // previously rent_epoch + #[allow(deprecated)] + { + assert_eq!(offset_of!(AccountInfo, _unused), 32); + let unused_ptr = (account_info_addr + 32) as *const u64; + unsafe { + assert_eq!(*unused_ptr, 0); + } + } + + // is_signer + assert_eq!(offset_of!(AccountInfo, is_signer), 40); + let is_signer_ptr = (account_info_addr + 40) as *const bool; + unsafe { + assert!(*is_signer_ptr); + } + + // is_writable + assert_eq!(offset_of!(AccountInfo, is_writable), 41); + let is_writable_ptr = (account_info_addr + 41) as *const bool; + unsafe { + assert!(!*is_writable_ptr); + } + + // executable + assert_eq!(offset_of!(AccountInfo, executable), 42); + let executable_ptr = (account_info_addr + 42) as *const bool; + unsafe { + assert!(*executable_ptr); + } +} + #[cfg(test)] mod tests { use { @@ -435,11 +483,11 @@ mod tests { let d5 = &mut [0u8]; let infos = &[ - AccountInfo::new(&k1, false, false, l1, d1, &k1, false, 0), - AccountInfo::new(&k2, false, false, l2, d2, &k2, false, 0), - AccountInfo::new(&k3, false, false, l3, d3, &k3, false, 0), - AccountInfo::new(&k4, false, false, l4, d4, &k4, false, 0), - AccountInfo::new(&k5, false, false, l5, d5, &k5, false, 0), + AccountInfo::new(&k1, false, false, l1, d1, &k1, false), + AccountInfo::new(&k2, false, false, l2, d2, &k2, false), + AccountInfo::new(&k3, false, false, l3, d3, &k3, false), + AccountInfo::new(&k4, false, false, l4, d4, &k4, false), + AccountInfo::new(&k5, false, false, l5, d5, &k5, false), ]; let infos_iter = &mut infos.iter(); let info1 = next_account_info(infos_iter).unwrap(); @@ -458,7 +506,7 @@ mod tests { let k = Pubkey::new_unique(); let l = &mut 0; let d = &mut [0u8]; - let info = AccountInfo::new(&k, false, false, l, d, &k, false, 0); + let info = AccountInfo::new(&k, false, false, l, d, &k, false); assert_eq!(info.key, info.as_ref().key); } @@ -468,7 +516,7 @@ mod tests { let mut lamports = 42; let mut data = vec![5; 80]; let data_str = format!("{:?}", Hex(&data[..MAX_DEBUG_ACCOUNT_DATA])); - let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false, 0); + let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false); assert_eq!( format!("{info:?}"), format!( @@ -478,7 +526,6 @@ mod tests { is_signer: {}, \ is_writable: {}, \ executable: {}, \ - rent_epoch: {}, \ lamports: {}, \ data.len: {}, \ data: {}, .. }}", @@ -487,7 +534,6 @@ mod tests { false, false, false, - 0, lamports, data.len(), data_str, @@ -496,7 +542,7 @@ mod tests { let mut data = vec![5; 40]; let data_str = format!("{:?}", Hex(&data)); - let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false, 0); + let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false); assert_eq!( format!("{info:?}"), format!( @@ -506,7 +552,6 @@ mod tests { is_signer: {}, \ is_writable: {}, \ executable: {}, \ - rent_epoch: {}, \ lamports: {}, \ data.len: {}, \ data: {}, .. }}", @@ -515,7 +560,6 @@ mod tests { false, false, false, - 0, lamports, data.len(), data_str, @@ -523,7 +567,7 @@ mod tests { ); let mut data = vec![]; - let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false, 0); + let info = AccountInfo::new(&key, false, false, &mut lamports, &mut data, &key, false); assert_eq!( format!("{info:?}"), format!( @@ -533,7 +577,6 @@ mod tests { is_signer: {}, \ is_writable: {}, \ executable: {}, \ - rent_epoch: {}, \ lamports: {}, \ data.len: {}, .. }}", key, @@ -541,10 +584,14 @@ mod tests { false, false, false, - 0, lamports, data.len(), ) ); } + + #[test] + fn test_layout_assumptions() { + super::check_type_assumptions(); + } } diff --git a/account/Cargo.toml b/account/Cargo.toml index 1534c8c38..2e04dc48b 100644 --- a/account/Cargo.toml +++ b/account/Cargo.toml @@ -15,12 +15,7 @@ all-features = true rustdoc-args = ["--cfg=docsrs"] [features] -bincode = [ - "dep:bincode", - "dep:solana-sysvar", - "solana-instruction/serde", - "serde", -] +bincode = ["dep:bincode", "dep:solana-sysvar", "serde"] dev-context-only-utils = ["bincode", "dep:qualifier_attr"] frozen-abi = [ "dep:solana-frozen-abi", @@ -45,7 +40,7 @@ solana-account-info = { workspace = true } solana-clock = { workspace = true } solana-frozen-abi = { workspace = true, optional = true } solana-frozen-abi-macro = { workspace = true, optional = true } -solana-instruction = { workspace = true } +solana-instruction-error = { workspace = true } solana-logger = { workspace = true, optional = true } solana-pubkey = { workspace = true } solana-sdk-ids = { workspace = true } diff --git a/account/src/lib.rs b/account/src/lib.rs index 1a9042c80..f4edae6de 100644 --- a/account/src/lib.rs +++ b/account/src/lib.rs @@ -9,11 +9,11 @@ use serde::ser::{Serialize, Serializer}; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; #[cfg(feature = "bincode")] -use solana_sysvar::Sysvar; +use solana_sysvar::SysvarSerialize; use { solana_account_info::{debug_account_data::*, AccountInfo}, solana_clock::{Epoch, INITIAL_RENT_EPOCH}, - solana_instruction::error::LamportsError, + solana_instruction_error::LamportsError, solana_pubkey::Pubkey, solana_sdk_ids::{bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, loader_v4}, std::{ @@ -33,7 +33,7 @@ pub mod state_traits; #[cfg_attr( feature = "frozen-abi", derive(AbiExample), - frozen_abi(digest = "2SUJNHbXMPWrsSXmDTFc4VHx2XQ85fT5Leabefh5Nwe7") + frozen_abi(digest = "62EqVoynUFvuui7DVfqWCvZP7bxKGJGioeSBnWrdjRME") )] #[cfg_attr( feature = "serde", @@ -70,7 +70,7 @@ mod account_serialize { #[cfg_attr( feature = "frozen-abi", derive(AbiExample), - frozen_abi(digest = "2SUJNHbXMPWrsSXmDTFc4VHx2XQ85fT5Leabefh5Nwe7") + frozen_abi(digest = "62EqVoynUFvuui7DVfqWCvZP7bxKGJGioeSBnWrdjRME") )] #[derive(serde_derive::Serialize)] #[serde(rename_all = "camelCase")] @@ -718,7 +718,7 @@ pub type InheritableAccountFields = (u64, Epoch); pub const DUMMY_INHERITABLE_ACCOUNT_FIELDS: InheritableAccountFields = (1, INITIAL_RENT_EPOCH); #[cfg(feature = "bincode")] -pub fn create_account_with_fields( +pub fn create_account_with_fields( sysvar: &S, (lamports, rent_epoch): InheritableAccountFields, ) -> Account { @@ -730,13 +730,13 @@ pub fn create_account_with_fields( } #[cfg(feature = "bincode")] -pub fn create_account_for_test(sysvar: &S) -> Account { +pub fn create_account_for_test(sysvar: &S) -> Account { create_account_with_fields(sysvar, DUMMY_INHERITABLE_ACCOUNT_FIELDS) } #[cfg(feature = "bincode")] /// Create an `Account` from a `Sysvar`. -pub fn create_account_shared_data_with_fields( +pub fn create_account_shared_data_with_fields( sysvar: &S, fields: InheritableAccountFields, ) -> AccountSharedData { @@ -744,7 +744,7 @@ pub fn create_account_shared_data_with_fields( } #[cfg(feature = "bincode")] -pub fn create_account_shared_data_for_test(sysvar: &S) -> AccountSharedData { +pub fn create_account_shared_data_for_test(sysvar: &S) -> AccountSharedData { AccountSharedData::from(create_account_with_fields( sysvar, DUMMY_INHERITABLE_ACCOUNT_FIELDS, @@ -753,26 +753,28 @@ pub fn create_account_shared_data_for_test(sysvar: &S) -> AccountShar #[cfg(feature = "bincode")] /// Create a `Sysvar` from an `Account`'s data. -pub fn from_account(account: &T) -> Option { +pub fn from_account(account: &T) -> Option { bincode::deserialize(account.data()).ok() } #[cfg(feature = "bincode")] /// Serialize a `Sysvar` into an `Account`'s data. -pub fn to_account(sysvar: &S, account: &mut T) -> Option<()> { +pub fn to_account( + sysvar: &S, + account: &mut T, +) -> Option<()> { bincode::serialize_into(account.data_as_mut_slice(), sysvar).ok() } /// Return the information required to construct an `AccountInfo`. Used by the /// `AccountInfo` conversion implementations. impl solana_account_info::Account for Account { - fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch) { + fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool) { ( &mut self.lamports, &mut self.data, &self.owner, self.executable, - self.rent_epoch, ) } } @@ -792,7 +794,6 @@ pub fn create_is_signer_account_infos<'a>( &mut account.data, &account.owner, account.executable, - account.rent_epoch, ) }) .collect() diff --git a/account/src/state_traits.rs b/account/src/state_traits.rs index 9b44e43ea..a7852a9a6 100644 --- a/account/src/state_traits.rs +++ b/account/src/state_traits.rs @@ -3,7 +3,7 @@ use { crate::{Account, AccountSharedData}, bincode::ErrorKind, - solana_instruction::error::InstructionError, + solana_instruction_error::InstructionError, std::cell::Ref, }; diff --git a/address-lookup-table-interface/Cargo.toml b/address-lookup-table-interface/Cargo.toml index 814480e2c..9a416b119 100644 --- a/address-lookup-table-interface/Cargo.toml +++ b/address-lookup-table-interface/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-address-lookup-table-interface" description = "Solana address lookup table interface." documentation = "https://docs.rs/solana-address-lookup-table-interface" version = "2.2.2" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -18,6 +19,7 @@ rustdoc-args = ["--cfg=docsrs"] bincode = [ "dep:bincode", "dep:solana-instruction", + "dep:solana-instruction-error", "serde", "solana-instruction/bincode", ] @@ -39,6 +41,7 @@ solana-frozen-abi-macro = { workspace = true, features = [ "frozen-abi", ], optional = true } solana-instruction = { workspace = true, features = ["std"], optional = true } +solana-instruction-error = { workspace = true, optional = true } solana-pubkey = { workspace = true } solana-sdk-ids = { workspace = true } solana-slot-hashes = { workspace = true } diff --git a/address-lookup-table-interface/src/error.rs b/address-lookup-table-interface/src/error.rs index f6323ae69..44aaba5a3 100644 --- a/address-lookup-table-interface/src/error.rs +++ b/address-lookup-table-interface/src/error.rs @@ -15,7 +15,7 @@ pub enum AddressLookupError { InvalidLookupIndex, } -impl std::error::Error for AddressLookupError {} +impl core::error::Error for AddressLookupError {} impl fmt::Display for AddressLookupError { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> fmt::Result { diff --git a/address-lookup-table-interface/src/instruction.rs b/address-lookup-table-interface/src/instruction.rs index 76650e705..351c88a3c 100644 --- a/address-lookup-table-interface/src/instruction.rs +++ b/address-lookup-table-interface/src/instruction.rs @@ -105,24 +105,6 @@ fn create_lookup_table_common( (instruction, lookup_table_address) } -/// Constructs an instruction to create a table account and returns -/// the instruction and the table account's derived address. -/// -/// # Note -/// -/// This instruction requires the authority to be a signer but -/// in v1.12 the address lookup table program will no longer require -/// the authority to sign the transaction. -#[deprecated(since = "2.2.0", note = "use `create_lookup_table` instead")] -#[cfg(feature = "bincode")] -pub fn create_lookup_table_signed( - authority_address: Pubkey, - payer_address: Pubkey, - recent_slot: Slot, -) -> (Instruction, Pubkey) { - create_lookup_table_common(authority_address, payer_address, recent_slot, true) -} - /// Constructs an instruction to create a table account and returns /// the instruction and the table account's derived address. /// diff --git a/address-lookup-table-interface/src/state.rs b/address-lookup-table-interface/src/state.rs index 70e46a194..ace7790e8 100644 --- a/address-lookup-table-interface/src/state.rs +++ b/address-lookup-table-interface/src/state.rs @@ -3,7 +3,7 @@ use serde_derive::{Deserialize, Serialize}; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{AbiEnumVisitor, AbiExample}; #[cfg(feature = "bincode")] -use solana_instruction::error::InstructionError; +use solana_instruction_error::InstructionError; use { crate::error::AddressLookupError, solana_clock::Slot, diff --git a/address/Cargo.toml b/address/Cargo.toml new file mode 100644 index 000000000..9e28c7877 --- /dev/null +++ b/address/Cargo.toml @@ -0,0 +1,82 @@ +[package] +name = "solana-address" +description = "Solana account addresses" +documentation = "https://docs.rs/solana-address" +version = "0.1.0" +rust-version = "1.81.0" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[features] +atomic = ["dep:solana-atomic-u64"] +borsh = ["dep:borsh", "std"] +bytemuck = ["dep:bytemuck", "dep:bytemuck_derive"] +curve25519 = ["dep:curve25519-dalek", "error", "sha2"] +decode = ["dep:five8", "dep:five8_const", "error"] +dev-context-only-utils = ["dep:arbitrary", "rand"] +error = ["dep:solana-program-error"] +frozen-abi = [ + "dep:solana-frozen-abi", + "dep:solana-frozen-abi-macro", + "dep:solana-program-error", + "std", +] +rand = ["dep:rand", "atomic", "std"] +sanitize = ["dep:solana-sanitize"] +serde = ["dep:serde", "dep:serde_derive"] +sha2 = ["dep:solana-sha256-hasher", "error"] +std = ["decode"] +syscalls = ["dep:solana-define-syscall", "error"] + +[dependencies] +arbitrary = { workspace = true, features = ["derive"], optional = true } +borsh = { workspace = true, optional = true } +bytemuck = { workspace = true, optional = true } +bytemuck_derive = { workspace = true, optional = true } +five8 = { workspace = true, optional = true } +five8_const = { workspace = true, optional = true } +rand = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +solana-atomic-u64 = { workspace = true, optional = true } +solana-frozen-abi = { workspace = true, features = ["frozen-abi"], optional = true } +solana-frozen-abi-macro = { workspace = true, features = ["frozen-abi"], optional = true } +solana-program-error = { workspace = true, optional = true } +solana-sanitize = { workspace = true, optional = true } + +[target.'cfg(not(target_os = "solana"))'.dependencies] +curve25519-dalek = { workspace = true, optional = true } +solana-sha256-hasher = { workspace = true, features = ["sha2"], optional = true } + +[target.'cfg(target_os = "solana")'.dependencies] +solana-define-syscall = { workspace = true, optional = true } +solana-sha256-hasher = { workspace = true, optional = true } + +[dev-dependencies] +anyhow = { workspace = true } +solana-account-info = { path = "../account-info" } +solana-address = { path = ".", features = [ + "atomic", + "borsh", + "curve25519", + "decode", + "dev-context-only-utils", + "error", + "sanitize", + "std", + "syscalls" +] } +solana-cpi = { path = "../cpi" } +solana-example-mocks = { path = "../example-mocks" } +solana-hash = { workspace = true } +solana-instruction = { path = "../instruction", features = ["borsh"] } +solana-program-error = { workspace = true, features = ["borsh"] } +solana-system-interface = { path = "../system-interface", features = ["bincode"] } +strum = { workspace = true } +strum_macros = { workspace = true } + +[lints] +workspace = true diff --git a/address/src/error.rs b/address/src/error.rs new file mode 100644 index 000000000..6a047fd5b --- /dev/null +++ b/address/src/error.rs @@ -0,0 +1,75 @@ +use {core::fmt, solana_program_error::ProgramError}; + +#[cfg_attr(feature = "serde", derive(serde_derive::Serialize))] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AddressError { + /// Length of the seed is too long for address generation + MaxSeedLengthExceeded, + InvalidSeeds, + IllegalOwner, +} + +impl core::error::Error for AddressError {} + +impl fmt::Display for AddressError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + AddressError::MaxSeedLengthExceeded => { + f.write_str("Length of the seed is too long for address generation") + } + AddressError::InvalidSeeds => { + f.write_str("Provided seeds do not result in a valid address") + } + AddressError::IllegalOwner => f.write_str("Provided owner is not allowed"), + } + } +} + +impl From for AddressError { + fn from(error: u64) -> Self { + match error { + 0 => AddressError::MaxSeedLengthExceeded, + 1 => AddressError::InvalidSeeds, + 2 => AddressError::IllegalOwner, + _ => panic!("Unsupported AddressError"), + } + } +} + +impl From for ProgramError { + fn from(error: AddressError) -> Self { + match error { + AddressError::MaxSeedLengthExceeded => Self::MaxSeedLengthExceeded, + AddressError::InvalidSeeds => Self::InvalidSeeds, + AddressError::IllegalOwner => Self::IllegalOwner, + } + } +} + +#[cfg_attr(feature = "serde", derive(serde_derive::Serialize))] +#[cfg(feature = "decode")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ParseAddressError { + WrongSize, + Invalid, +} + +#[cfg(feature = "decode")] +impl core::error::Error for ParseAddressError {} + +#[cfg(feature = "decode")] +impl fmt::Display for ParseAddressError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ParseAddressError::WrongSize => f.write_str("String is the wrong size"), + ParseAddressError::Invalid => f.write_str("Invalid Base58 string"), + } + } +} + +#[cfg(feature = "decode")] +impl From for ParseAddressError { + fn from(_: core::convert::Infallible) -> Self { + unreachable!("Infallible uninhabited"); + } +} diff --git a/address/src/hasher.rs b/address/src/hasher.rs new file mode 100644 index 000000000..922b91ec6 --- /dev/null +++ b/address/src/hasher.rs @@ -0,0 +1,140 @@ +use { + crate::ADDRESS_BYTES, + core::{ + cell::Cell, + hash::{BuildHasher, Hasher}, + mem, + }, + rand::{thread_rng, Rng}, +}; + +/// A faster, but less collision resistant hasher for addresses. +/// +/// Specialized hasher that uses a random 8 bytes subslice of the +/// address as the hash value. Should not be used when collisions +/// might be used to mount DOS attacks. +/// +/// Using this results in about 4x faster lookups in a typical hashmap. +#[derive(Default)] +pub struct AddressHasher { + offset: usize, + state: u64, +} + +impl Hasher for AddressHasher { + #[inline] + fn finish(&self) -> u64 { + self.state + } + #[inline] + fn write(&mut self, bytes: &[u8]) { + debug_assert_eq!( + bytes.len(), + ADDRESS_BYTES, + "This hasher is intended to be used with addresses and nothing else" + ); + // This slice/unwrap can never panic since offset is < ADDRESS_BYTES - mem::size_of::() + let chunk: &[u8; mem::size_of::()] = bytes + [self.offset..self.offset + mem::size_of::()] + .try_into() + .unwrap(); + self.state = u64::from_ne_bytes(*chunk); + } +} + +/// A builder for faster, but less collision resistant hasher for addresses. +/// +/// Initializes `AddressHasher` instances that use an 8-byte +/// slice of the address as the hash value. Should not be used when +/// collisions might be used to mount DOS attacks. +/// +/// Using this results in about 4x faster lookups in a typical hashmap. +#[derive(Clone)] +pub struct AddressHasherBuilder { + offset: usize, +} + +impl Default for AddressHasherBuilder { + /// Default construct the AddressHasherBuilder. + /// + /// The position of the slice is determined initially + /// through random draw and then by incrementing a thread-local + /// This way each hashmap can be expected to use a slightly different + /// slice. This is essentially the same mechanism as what is used by + /// `RandomState` + fn default() -> Self { + std::thread_local!(static OFFSET: Cell = { + let mut rng = thread_rng(); + Cell::new(rng.gen_range(0..ADDRESS_BYTES - mem::size_of::())) + }); + + let offset = OFFSET.with(|offset| { + let mut next_offset = offset.get() + 1; + if next_offset > ADDRESS_BYTES - mem::size_of::() { + next_offset = 0; + } + offset.set(next_offset); + next_offset + }); + AddressHasherBuilder { offset } + } +} + +impl BuildHasher for AddressHasherBuilder { + type Hasher = AddressHasher; + #[inline] + fn build_hasher(&self) -> Self::Hasher { + AddressHasher { + offset: self.offset, + state: 0, + } + } +} + +#[cfg(test)] +mod tests { + use { + super::AddressHasherBuilder, + crate::Address, + core::hash::{BuildHasher, Hasher}, + }; + #[test] + fn test_address_hasher_builder() { + let key = Address::new_unique(); + let builder = AddressHasherBuilder::default(); + let mut hasher1 = builder.build_hasher(); + let mut hasher2 = builder.build_hasher(); + hasher1.write(key.as_array()); + hasher2.write(key.as_array()); + assert_eq!( + hasher1.finish(), + hasher2.finish(), + "Hashers made with same builder should be identical" + ); + // Make sure that when we make new builders we get different slices + // chosen for hashing + let builder2 = AddressHasherBuilder::default(); + for _ in 0..64 { + let mut hasher3 = builder2.build_hasher(); + hasher3.write(key.as_array()); + std::dbg!(hasher1.finish()); + std::dbg!(hasher3.finish()); + if hasher1.finish() != hasher3.finish() { + return; + } + } + panic!("Hashers built with different builder should be different due to random offset"); + } + + #[test] + fn test_address_hasher() { + let key1 = Address::new_unique(); + let key2 = Address::new_unique(); + let builder = AddressHasherBuilder::default(); + let mut hasher1 = builder.build_hasher(); + let mut hasher2 = builder.build_hasher(); + hasher1.write(key1.as_array()); + hasher2.write(key2.as_array()); + assert_ne!(hasher1.finish(), hasher2.finish()); + } +} diff --git a/address/src/lib.rs b/address/src/lib.rs new file mode 100644 index 000000000..ac9e97d85 --- /dev/null +++ b/address/src/lib.rs @@ -0,0 +1,612 @@ +//! Address representation for Solana. +//! +//! An address is a sequence of 32 bytes, often shown as a base58 encoded string +//! (e.g. 14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5). + +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] +#![allow(clippy::arithmetic_side_effects)] + +#[cfg(feature = "error")] +pub mod error; +#[cfg(feature = "rand")] +mod hasher; +#[cfg(any(feature = "curve25519", feature = "syscalls"))] +pub mod syscalls; + +#[cfg(feature = "sha2")] +use crate::error::AddressError; +#[cfg(feature = "decode")] +use crate::error::ParseAddressError; +#[cfg(all(feature = "rand", not(target_os = "solana")))] +pub use crate::hasher::{AddressHasher, AddressHasherBuilder}; + +#[cfg(feature = "std")] +extern crate std; +#[cfg(feature = "dev-context-only-utils")] +use arbitrary::Arbitrary; +#[cfg(feature = "bytemuck")] +use bytemuck_derive::{Pod, Zeroable}; +#[cfg(feature = "decode")] +use core::str::FromStr; +use core::{ + array, + convert::TryFrom, + hash::{Hash, Hasher}, +}; +#[cfg(feature = "serde")] +use serde_derive::{Deserialize, Serialize}; +#[cfg(feature = "std")] +use std::vec::Vec; +#[cfg(feature = "borsh")] +use { + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + std::string::ToString, +}; + +/// Number of bytes in an address. +pub const ADDRESS_BYTES: usize = 32; +/// maximum length of derived `Address` seed +pub const MAX_SEED_LEN: usize = 32; +/// Maximum number of seeds +pub const MAX_SEEDS: usize = 16; +#[cfg(feature = "decode")] +/// Maximum string length of a base58 encoded address. +const MAX_BASE58_LEN: usize = 44; + +#[cfg(feature = "sha2")] +const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress"; + +/// The address of a [Solana account][acc]. +/// +/// Some account addresses are [ed25519] public keys, with corresponding secret +/// keys that are managed off-chain. Often, though, account addresses do not +/// have corresponding secret keys — as with [_program derived +/// addresses_][pdas] — or the secret key is not relevant to the operation +/// of a program, and may have even been disposed of. As running Solana programs +/// can not safely create or manage secret keys, the full [`Keypair`] is not +/// defined in `solana-program` but in `solana-sdk`. +/// +/// [acc]: https://solana.com/docs/core/accounts +/// [ed25519]: https://ed25519.cr.yp.to/ +/// [pdas]: https://solana.com/docs/core/cpi#program-derived-addresses +/// [`Keypair`]: https://docs.rs/solana-sdk/latest/solana_sdk/signer/keypair/struct.Keypair.html +#[repr(transparent)] +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr( + feature = "borsh", + derive(BorshSerialize, BorshDeserialize), + borsh(crate = "borsh") +)] +#[cfg_attr(all(feature = "borsh", feature = "std"), derive(BorshSchema))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))] +#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))] +pub struct Address(pub(crate) [u8; 32]); + +#[cfg(feature = "sanitize")] +impl solana_sanitize::Sanitize for Address {} + +#[cfg(feature = "decode")] +impl FromStr for Address { + type Err = ParseAddressError; + + fn from_str(s: &str) -> Result { + use five8::DecodeError; + if s.len() > MAX_BASE58_LEN { + return Err(ParseAddressError::WrongSize); + } + let mut bytes = [0; ADDRESS_BYTES]; + five8::decode_32(s, &mut bytes).map_err(|e| match e { + DecodeError::InvalidChar(_) => ParseAddressError::Invalid, + DecodeError::TooLong + | DecodeError::TooShort + | DecodeError::LargestTermTooHigh + | DecodeError::OutputTooLong => ParseAddressError::WrongSize, + })?; + Ok(Address(bytes)) + } +} + +/// Custom impl of Hash for Address. +/// +/// This allows us to skip hashing the length of the address +/// which is always the same anyway. +impl Hash for Address { + fn hash(&self, state: &mut H) { + state.write(self.as_array()); + } +} + +impl From<&Address> for Address { + #[inline] + fn from(value: &Address) -> Self { + *value + } +} + +impl From<[u8; 32]> for Address { + #[inline] + fn from(from: [u8; 32]) -> Self { + Self(from) + } +} + +impl TryFrom<&[u8]> for Address { + type Error = array::TryFromSliceError; + + #[inline] + fn try_from(address: &[u8]) -> Result { + <[u8; 32]>::try_from(address).map(Self::from) + } +} + +#[cfg(feature = "std")] +impl TryFrom> for Address { + type Error = Vec; + + #[inline] + fn try_from(address: Vec) -> Result { + <[u8; 32]>::try_from(address).map(Self::from) + } +} +#[cfg(feature = "decode")] +impl TryFrom<&str> for Address { + type Error = ParseAddressError; + fn try_from(s: &str) -> Result { + Address::from_str(s) + } +} + +// If target_os = "solana", then this panics so there are no dependencies. +// When target_os != "solana", this should be opt-in so users +// don't need the curve25519 dependency. +#[cfg(any(target_os = "solana", feature = "curve25519"))] +#[allow(clippy::used_underscore_binding)] +pub fn bytes_are_curve_point>(_bytes: T) -> bool { + #[cfg(not(target_os = "solana"))] + { + let Ok(compressed_edwards_y) = + curve25519_dalek::edwards::CompressedEdwardsY::from_slice(_bytes.as_ref()) + else { + return false; + }; + compressed_edwards_y.decompress().is_some() + } + #[cfg(target_os = "solana")] + unimplemented!(); +} + +impl Address { + pub const fn new_from_array(address_array: [u8; 32]) -> Self { + Self(address_array) + } + + #[cfg(feature = "decode")] + /// Decode a string into an `Address`, usable in a const context + pub const fn from_str_const(s: &str) -> Self { + let id_array = five8_const::decode_32_const(s); + Address::new_from_array(id_array) + } + + #[cfg(feature = "atomic")] + /// Create an unique `Address` for tests and benchmarks. + pub fn new_unique() -> Self { + use solana_atomic_u64::AtomicU64; + static I: AtomicU64 = AtomicU64::new(1); + type T = u32; + const COUNTER_BYTES: usize = core::mem::size_of::(); + let mut b = [0u8; ADDRESS_BYTES]; + #[cfg(feature = "std")] + let mut i = I.fetch_add(1) as T; + #[cfg(not(feature = "std"))] + let i = I.fetch_add(1) as T; + // use big endian representation to ensure that recent unique addresses + // are always greater than less recent unique addresses. + b[0..COUNTER_BYTES].copy_from_slice(&i.to_be_bytes()); + // fill the rest of the address with pseudorandom numbers to make + // data statistically similar to real addresses. + #[cfg(feature = "std")] + { + let mut hash = std::hash::DefaultHasher::new(); + for slice in b[COUNTER_BYTES..].chunks_mut(COUNTER_BYTES) { + hash.write_u32(i); + i += 1; + slice.copy_from_slice(&hash.finish().to_ne_bytes()[0..COUNTER_BYTES]); + } + } + // if std is not available, just replicate last byte of the counter. + // this is not as good as a proper hash, but at least it is uniform + #[cfg(not(feature = "std"))] + { + for b in b[COUNTER_BYTES..].iter_mut() { + *b = (i & 0xFF) as u8; + } + } + Self::from(b) + } + + // If target_os = "solana", then the solana_sha256_hasher crate will use + // syscalls which bring no dependencies. + // When target_os != "solana", this should be opt-in so users + // don't need the sha2 dependency. + #[cfg(feature = "sha2")] + pub fn create_with_seed( + base: &Address, + seed: &str, + owner: &Address, + ) -> Result { + if seed.len() > MAX_SEED_LEN { + return Err(AddressError::MaxSeedLengthExceeded); + } + + let owner = owner.as_ref(); + if owner.len() >= PDA_MARKER.len() { + let slice = &owner[owner.len() - PDA_MARKER.len()..]; + if slice == PDA_MARKER { + return Err(AddressError::IllegalOwner); + } + } + let hash = solana_sha256_hasher::hashv(&[base.as_ref(), seed.as_ref(), owner]); + Ok(Address::from(hash.to_bytes())) + } + + pub const fn to_bytes(self) -> [u8; 32] { + self.0 + } + + /// Return a reference to the `Address`'s byte array. + #[inline(always)] + pub const fn as_array(&self) -> &[u8; 32] { + &self.0 + } + + // If target_os = "solana", then this panics so there are no dependencies. + // When target_os != "solana", this should be opt-in so users + // don't need the curve25519 dependency. + #[cfg(any(target_os = "solana", feature = "curve25519"))] + pub fn is_on_curve(&self) -> bool { + bytes_are_curve_point(self) + } +} + +impl AsRef<[u8]> for Address { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Address { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +#[cfg(feature = "decode")] +fn write_as_base58(f: &mut core::fmt::Formatter, p: &Address) -> core::fmt::Result { + let mut out = [0u8; MAX_BASE58_LEN]; + let len = five8::encode_32(&p.0, &mut out) as usize; + // any sequence of base58 chars is valid utf8 + let as_str = unsafe { core::str::from_utf8_unchecked(&out[..len]) }; + f.write_str(as_str) +} + +#[cfg(feature = "decode")] +impl core::fmt::Debug for Address { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write_as_base58(f, self) + } +} + +#[cfg(feature = "decode")] +impl core::fmt::Display for Address { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write_as_base58(f, self) + } +} + +/// Convenience macro to define a static `Address` value. +/// +/// Input: a single literal base58 string representation of an `Address`. +/// +/// # Example +/// +/// ``` +/// use std::str::FromStr; +/// use solana_address::{address, Address}; +/// +/// static ID: Address = address!("My11111111111111111111111111111111111111111"); +/// +/// let my_id = Address::from_str("My11111111111111111111111111111111111111111").unwrap(); +/// assert_eq!(ID, my_id); +/// ``` +#[macro_export] +macro_rules! address { + ($input:literal) => { + $crate::Address::from_str_const($input) + }; +} + +#[cfg(test)] +mod tests { + use {super::*, core::str::from_utf8, std::string::String}; + + fn encode_address(address: &[u8; 32]) -> String { + let mut buffer = [0u8; 44]; + let count = five8::encode_32(address, &mut buffer); + from_utf8(&buffer[..count as usize]).unwrap().to_string() + } + + #[test] + fn test_new_unique() { + assert!(Address::new_unique() != Address::new_unique()); + } + + #[test] + fn address_fromstr() { + let address = Address::new_unique(); + let mut address_base58_str = encode_address(&address.0); + + assert_eq!(address_base58_str.parse::
(), Ok(address)); + + address_base58_str.push_str(&encode_address(&address.0)); + assert_eq!( + address_base58_str.parse::
(), + Err(ParseAddressError::WrongSize) + ); + + address_base58_str.truncate(address_base58_str.len() / 2); + assert_eq!(address_base58_str.parse::
(), Ok(address)); + + address_base58_str.truncate(address_base58_str.len() / 2); + assert_eq!( + address_base58_str.parse::
(), + Err(ParseAddressError::WrongSize) + ); + + let mut address_base58_str = encode_address(&address.0); + assert_eq!(address_base58_str.parse::
(), Ok(address)); + + // throw some non-base58 stuff in there + address_base58_str.replace_range(..1, "I"); + assert_eq!( + address_base58_str.parse::
(), + Err(ParseAddressError::Invalid) + ); + + // too long input string + // longest valid encoding + let mut too_long = encode_address(&[255u8; ADDRESS_BYTES]); + // and one to grow on + too_long.push('1'); + assert_eq!( + too_long.parse::
(), + Err(ParseAddressError::WrongSize) + ); + } + + #[test] + fn test_create_with_seed() { + assert!( + Address::create_with_seed(&Address::new_unique(), "☉", &Address::new_unique()).is_ok() + ); + assert_eq!( + Address::create_with_seed( + &Address::new_unique(), + from_utf8(&[127; MAX_SEED_LEN + 1]).unwrap(), + &Address::new_unique() + ), + Err(AddressError::MaxSeedLengthExceeded) + ); + assert!(Address::create_with_seed( + &Address::new_unique(), + "\ + \u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\ + ", + &Address::new_unique() + ) + .is_ok()); + // utf-8 abuse ;) + assert_eq!( + Address::create_with_seed( + &Address::new_unique(), + "\ + x\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\ + ", + &Address::new_unique() + ), + Err(AddressError::MaxSeedLengthExceeded) + ); + + assert!(Address::create_with_seed( + &Address::new_unique(), + from_utf8(&[0; MAX_SEED_LEN]).unwrap(), + &Address::new_unique(), + ) + .is_ok()); + + assert!( + Address::create_with_seed(&Address::new_unique(), "", &Address::new_unique(),).is_ok() + ); + + assert_eq!( + Address::create_with_seed( + &Address::default(), + "limber chicken: 4/45", + &Address::default(), + ), + Ok("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq" + .parse() + .unwrap()) + ); + } + + #[test] + fn test_create_program_address() { + let exceeded_seed = &[127; MAX_SEED_LEN + 1]; + let max_seed = &[0; MAX_SEED_LEN]; + let exceeded_seeds: &[&[u8]] = &[ + &[1], + &[2], + &[3], + &[4], + &[5], + &[6], + &[7], + &[8], + &[9], + &[10], + &[11], + &[12], + &[13], + &[14], + &[15], + &[16], + &[17], + ]; + let max_seeds: &[&[u8]] = &[ + &[1], + &[2], + &[3], + &[4], + &[5], + &[6], + &[7], + &[8], + &[9], + &[10], + &[11], + &[12], + &[13], + &[14], + &[15], + &[16], + ]; + let program_id = Address::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap(); + let public_key = Address::from_str("SeedPubey1111111111111111111111111111111111").unwrap(); + + assert_eq!( + Address::create_program_address(&[exceeded_seed], &program_id), + Err(AddressError::MaxSeedLengthExceeded) + ); + assert_eq!( + Address::create_program_address(&[b"short_seed", exceeded_seed], &program_id), + Err(AddressError::MaxSeedLengthExceeded) + ); + assert!(Address::create_program_address(&[max_seed], &program_id).is_ok()); + assert_eq!( + Address::create_program_address(exceeded_seeds, &program_id), + Err(AddressError::MaxSeedLengthExceeded) + ); + assert!(Address::create_program_address(max_seeds, &program_id).is_ok()); + assert_eq!( + Address::create_program_address(&[b"", &[1]], &program_id), + Ok("BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe" + .parse() + .unwrap()) + ); + assert_eq!( + Address::create_program_address(&["☉".as_ref(), &[0]], &program_id), + Ok("13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19" + .parse() + .unwrap()) + ); + assert_eq!( + Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id), + Ok("2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk" + .parse() + .unwrap()) + ); + assert_eq!( + Address::create_program_address(&[public_key.as_ref(), &[1]], &program_id), + Ok("976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL" + .parse() + .unwrap()) + ); + assert_ne!( + Address::create_program_address(&[b"Talking", b"Squirrels"], &program_id).unwrap(), + Address::create_program_address(&[b"Talking"], &program_id).unwrap(), + ); + } + + #[test] + fn test_address_off_curve() { + // try a bunch of random input, all successful generated program + // addresses must land off the curve and be unique + let mut addresses = std::vec![]; + for _ in 0..1_000 { + let program_id = Address::new_unique(); + let bytes1 = rand::random::<[u8; 10]>(); + let bytes2 = rand::random::<[u8; 32]>(); + if let Ok(program_address) = + Address::create_program_address(&[&bytes1, &bytes2], &program_id) + { + assert!(!program_address.is_on_curve()); + assert!(!addresses.contains(&program_address)); + addresses.push(program_address); + } + } + } + + #[test] + fn test_find_program_address() { + for _ in 0..1_000 { + let program_id = Address::new_unique(); + let (address, bump_seed) = + Address::find_program_address(&[b"Lil'", b"Bits"], &program_id); + assert_eq!( + address, + Address::create_program_address(&[b"Lil'", b"Bits", &[bump_seed]], &program_id) + .unwrap() + ); + } + } + + fn address_from_seed_by_marker(marker: &[u8]) -> Result { + let key = Address::new_unique(); + let owner = Address::default(); + + let mut to_fake = owner.to_bytes().to_vec(); + to_fake.extend_from_slice(marker); + + let seed = from_utf8(&to_fake[..to_fake.len() - 32]).expect("not utf8"); + let base = &Address::try_from(&to_fake[to_fake.len() - 32..]).unwrap(); + + Address::create_with_seed(&key, seed, base) + } + + #[test] + fn test_create_with_seed_rejects_illegal_owner() { + assert_eq!( + address_from_seed_by_marker(PDA_MARKER), + Err(AddressError::IllegalOwner) + ); + assert!(address_from_seed_by_marker(&PDA_MARKER[1..]).is_ok()); + } + + #[test] + fn test_as_array() { + let bytes = [1u8; 32]; + let key = Address::from(bytes); + assert_eq!(key.as_array(), &bytes); + assert_eq!(key.as_array(), &key.to_bytes()); + // Sanity check: ensure the pointer is the same. + assert_eq!(key.as_array().as_ptr(), key.0.as_ptr()); + } + + #[test] + fn test_address_macro() { + const ADDRESS: Address = + Address::from_str_const("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"); + assert_eq!( + address!("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"), + ADDRESS + ); + assert_eq!( + Address::from_str("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq").unwrap(), + ADDRESS + ); + } +} diff --git a/address/src/syscalls.rs b/address/src/syscalls.rs new file mode 100644 index 000000000..066eca496 --- /dev/null +++ b/address/src/syscalls.rs @@ -0,0 +1,447 @@ +#[cfg(all(not(target_os = "solana"), feature = "curve25519"))] +use crate::bytes_are_curve_point; +#[cfg(any(target_os = "solana", feature = "curve25519"))] +use crate::error::AddressError; +use crate::Address; +#[cfg(target_os = "solana")] +/// Syscall definitions used by `solana_address`. +pub use solana_define_syscall::definitions::{ + sol_create_program_address, sol_log_pubkey, sol_try_find_program_address, +}; + +/// Copied from `solana_program::entrypoint::SUCCESS` +/// to avoid a `solana_program` dependency +#[cfg(target_os = "solana")] +const SUCCESS: u64 = 0; + +impl Address { + #[cfg(any(target_os = "solana", feature = "std"))] + /// Log a `Address` from a program + pub fn log(&self) { + #[cfg(target_os = "solana")] + unsafe { + sol_log_pubkey(self.as_ref() as *const _ as *const u8) + }; + + #[cfg(not(target_os = "solana"))] + std::println!("{}", std::string::ToString::to_string(&self)); + } + + /// Find a valid [program derived address][pda] and its corresponding bump seed. + /// + /// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses + /// + /// Program derived addresses (PDAs) are account keys that only the program, + /// `program_id`, has the authority to sign. The address is of the same form + /// as a Solana `Address`, except they are ensured to not be on the ed25519 + /// curve and thus have no associated private key. When performing + /// cross-program invocations the program can "sign" for the key by calling + /// [`invoke_signed`] and passing the same seeds used to generate the + /// address, along with the calculated _bump seed_, which this function + /// returns as the second tuple element. The runtime will verify that the + /// program associated with this address is the caller and thus authorized + /// to be the signer. + /// + /// [`invoke_signed`]: https://docs.rs/solana-program/latest/solana_program/program/fn.invoke_signed.html + /// + /// The `seeds` are application-specific, and must be carefully selected to + /// uniquely derive accounts per application requirements. It is common to + /// use static strings and other addresses as seeds. + /// + /// Because the program address must not lie on the ed25519 curve, there may + /// be seed and program id combinations that are invalid. For this reason, + /// an extra seed (the bump seed) is calculated that results in a + /// point off the curve. The bump seed must be passed as an additional seed + /// when calling `invoke_signed`. + /// + /// The processes of finding a valid program address is by trial and error, + /// and even though it is deterministic given a set of inputs it can take a + /// variable amount of time to succeed across different inputs. This means + /// that when called from an on-chain program it may incur a variable amount + /// of the program's compute budget. Programs that are meant to be very + /// performant may not want to use this function because it could take a + /// considerable amount of time. Programs that are already at risk + /// of exceeding their compute budget should call this with care since + /// there is a chance that the program's budget may be occasionally + /// and unpredictably exceeded. + /// + /// As all account addresses accessed by an on-chain Solana program must be + /// explicitly passed to the program, it is typical for the PDAs to be + /// derived in off-chain client programs, avoiding the compute cost of + /// generating the address on-chain. The address may or may not then be + /// verified by re-deriving it on-chain, depending on the requirements of + /// the program. This verification may be performed without the overhead of + /// re-searching for the bump key by using the [`create_program_address`] + /// function. + /// + /// [`create_program_address`]: Address::create_program_address + /// + /// **Warning**: Because of the way the seeds are hashed there is a potential + /// for program address collisions for the same program id. The seeds are + /// hashed sequentially which means that seeds {"abcdef"}, {"abc", "def"}, + /// and {"ab", "cd", "ef"} will all result in the same program address given + /// the same program id. Since the chance of collision is local to a given + /// program id, the developer of that program must take care to choose seeds + /// that do not collide with each other. For seed schemes that are susceptible + /// to this type of hash collision, a common remedy is to insert separators + /// between seeds, e.g. transforming {"abc", "def"} into {"abc", "-", "def"}. + /// + /// # Panics + /// + /// Panics in the statistically improbable event that a bump seed could not be + /// found. Use [`try_find_program_address`] to handle this case. + /// + /// [`try_find_program_address`]: Address::try_find_program_address + /// + /// Panics if any of the following are true: + /// + /// - the number of provided seeds is greater than, _or equal to_, [`crate::MAX_SEEDS`], + /// - any individual seed's length is greater than [`crate::MAX_SEED_LEN`]. + /// + /// # Examples + /// + /// This example illustrates a simple case of creating a "vault" account + /// which is derived from the payer account, but owned by an on-chain + /// program. The program derived address is derived in an off-chain client + /// program, which invokes an on-chain Solana program that uses the address + /// to create a new account owned and controlled by the program itself. + /// + /// By convention, the on-chain program will be compiled for use in two + /// different contexts: both on-chain, to interpret a custom program + /// instruction as a Solana transaction; and off-chain, as a library, so + /// that clients can share the instruction data structure, constructors, and + /// other common code. + /// + /// First the on-chain Solana program: + /// + /// ``` + /// # use borsh::{BorshSerialize, BorshDeserialize}; + /// # use solana_account_info::{next_account_info, AccountInfo}; + /// # use solana_program_error::ProgramResult; + /// # use solana_cpi::invoke_signed; + /// # use solana_address::Address; + /// # use solana_system_interface::instruction::create_account; + /// // The custom instruction processed by our program. It includes the + /// // PDA's bump seed, which is derived by the client program. This + /// // definition is also imported into the off-chain client program. + /// // The computed address of the PDA will be passed to this program via + /// // the `accounts` vector of the `Instruction` type. + /// #[derive(BorshSerialize, BorshDeserialize, Debug)] + /// # #[borsh(crate = "borsh")] + /// pub struct InstructionData { + /// pub vault_bump_seed: u8, + /// pub lamports: u64, + /// } + /// + /// // The size in bytes of a vault account. The client program needs + /// // this information to calculate the quantity of lamports necessary + /// // to pay for the account's rent. + /// pub static VAULT_ACCOUNT_SIZE: u64 = 1024; + /// + /// // The entrypoint of the on-chain program, as provided to the + /// // `entrypoint!` macro. + /// fn process_instruction( + /// program_id: &Address, + /// accounts: &[AccountInfo], + /// instruction_data: &[u8], + /// ) -> ProgramResult { + /// let account_info_iter = &mut accounts.iter(); + /// let payer = next_account_info(account_info_iter)?; + /// // The vault PDA, derived from the payer's address + /// let vault = next_account_info(account_info_iter)?; + /// + /// let mut instruction_data = instruction_data; + /// let instr = InstructionData::deserialize(&mut instruction_data)?; + /// let vault_bump_seed = instr.vault_bump_seed; + /// let lamports = instr.lamports; + /// let vault_size = VAULT_ACCOUNT_SIZE; + /// + /// // Invoke the system program to create an account while virtually + /// // signing with the vault PDA, which is owned by this caller program. + /// invoke_signed( + /// &create_account( + /// &payer.key, + /// &vault.key, + /// lamports, + /// vault_size, + /// program_id, + /// ), + /// &[ + /// payer.clone(), + /// vault.clone(), + /// ], + /// // A slice of seed slices, each seed slice being the set + /// // of seeds used to generate one of the PDAs required by the + /// // callee program, the final seed being a single-element slice + /// // containing the `u8` bump seed. + /// &[ + /// &[ + /// b"vault", + /// payer.key.as_ref(), + /// &[vault_bump_seed], + /// ], + /// ] + /// )?; + /// + /// Ok(()) + /// } + /// ``` + /// + /// The client program: + /// + /// ``` + /// # use borsh::{BorshSerialize, BorshDeserialize}; + /// # use solana_example_mocks::{solana_sdk, solana_rpc_client}; + /// # use solana_address::Address; + /// # use solana_instruction::{AccountMeta, Instruction}; + /// # use solana_hash::Hash; + /// # use solana_sdk::{ + /// # signature::Keypair, + /// # signature::{Signer, Signature}, + /// # transaction::Transaction, + /// # }; + /// # use solana_rpc_client::rpc_client::RpcClient; + /// # use std::convert::TryFrom; + /// # use anyhow::Result; + /// # + /// # #[derive(BorshSerialize, BorshDeserialize, Debug)] + /// # #[borsh(crate = "borsh")] + /// # struct InstructionData { + /// # pub vault_bump_seed: u8, + /// # pub lamports: u64, + /// # } + /// # + /// # pub static VAULT_ACCOUNT_SIZE: u64 = 1024; + /// # + /// fn create_vault_account( + /// client: &RpcClient, + /// program_id: Address, + /// payer: &Keypair, + /// ) -> Result<()> { + /// // Derive the PDA from the payer account, a string representing the unique + /// // purpose of the account ("vault"), and the address of our on-chain program. + /// let (vault_address, vault_bump_seed) = Address::find_program_address( + /// &[b"vault", payer.pubkey().as_ref()], + /// &program_id + /// ); + /// + /// // Get the amount of lamports needed to pay for the vault's rent + /// let vault_account_size = usize::try_from(VAULT_ACCOUNT_SIZE)?; + /// let lamports = client.get_minimum_balance_for_rent_exemption(vault_account_size)?; + /// + /// // The on-chain program's instruction data, imported from that program's crate. + /// let instr_data = InstructionData { + /// vault_bump_seed, + /// lamports, + /// }; + /// + /// // The accounts required by both our on-chain program and the system program's + /// // `create_account` instruction, including the vault's address. + /// let accounts = vec![ + /// AccountMeta::new(payer.pubkey(), true), + /// AccountMeta::new(vault_address, false), + /// AccountMeta::new(solana_system_interface::program::ID, false), + /// ]; + /// + /// // Create the instruction by serializing our instruction data via borsh + /// let instruction = Instruction::new_with_borsh( + /// program_id, + /// &instr_data, + /// accounts, + /// ); + /// + /// let blockhash = client.get_latest_blockhash()?; + /// + /// let transaction = Transaction::new_signed_with_payer( + /// &[instruction], + /// Some(&payer.pubkey()), + /// &[payer], + /// blockhash, + /// ); + /// + /// client.send_and_confirm_transaction(&transaction)?; + /// + /// Ok(()) + /// } + /// # let program_id = Address::new_unique(); + /// # let payer = Keypair::new(); + /// # let client = RpcClient::new(String::new()); + /// # + /// # create_vault_account(&client, program_id, &payer)?; + /// # + /// # Ok::<(), anyhow::Error>(()) + /// ``` + // If target_os = "solana", then the function will use + // syscalls which bring no dependencies. + // When target_os != "solana", this should be opt-in so users + // don't need the curve25519 dependency. + #[cfg(any(target_os = "solana", feature = "curve25519"))] + pub fn find_program_address(seeds: &[&[u8]], program_id: &Address) -> (Address, u8) { + Self::try_find_program_address(seeds, program_id) + .unwrap_or_else(|| panic!("Unable to find a viable program address bump seed")) + } + + /// Find a valid [program derived address][pda] and its corresponding bump seed. + /// + /// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses + /// + /// The only difference between this method and [`find_program_address`] + /// is that this one returns `None` in the statistically improbable event + /// that a bump seed cannot be found; or if any of `find_program_address`'s + /// preconditions are violated. + /// + /// See the documentation for [`find_program_address`] for a full description. + /// + /// [`find_program_address`]: Address::find_program_address + // If target_os = "solana", then the function will use + // syscalls which bring no dependencies. + // When target_os != "solana", this should be opt-in so users + // don't need the curve25519 dependency. + #[cfg(any(target_os = "solana", feature = "curve25519"))] + #[allow(clippy::same_item_push)] + pub fn try_find_program_address( + seeds: &[&[u8]], + program_id: &Address, + ) -> Option<(Address, u8)> { + // Perform the calculation inline, calling this from within a program is + // not supported + #[cfg(not(target_os = "solana"))] + { + let mut bump_seed = [u8::MAX]; + for _ in 0..u8::MAX { + { + let mut seeds_with_bump = seeds.to_vec(); + seeds_with_bump.push(&bump_seed); + match Self::create_program_address(&seeds_with_bump, program_id) { + Ok(address) => return Some((address, bump_seed[0])), + Err(AddressError::InvalidSeeds) => (), + _ => break, + } + } + bump_seed[0] -= 1; + } + None + } + // Call via a system call to perform the calculation + #[cfg(target_os = "solana")] + { + let mut bytes = [0; 32]; + let mut bump_seed = u8::MAX; + let result = unsafe { + crate::syscalls::sol_try_find_program_address( + seeds as *const _ as *const u8, + seeds.len() as u64, + program_id as *const _ as *const u8, + &mut bytes as *mut _ as *mut u8, + &mut bump_seed as *mut _ as *mut u8, + ) + }; + match result { + SUCCESS => Some((Address::from(bytes), bump_seed)), + _ => None, + } + } + } + + /// Create a valid [program derived address][pda] without searching for a bump seed. + /// + /// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses + /// + /// Because this function does not create a bump seed, it may unpredictably + /// return an error for any given set of seeds and is not generally suitable + /// for creating program derived addresses. + /// + /// However, it can be used for efficiently verifying that a set of seeds plus + /// bump seed generated by [`find_program_address`] derives a particular + /// address as expected. See the example for details. + /// + /// See the documentation for [`find_program_address`] for a full description + /// of program derived addresses and bump seeds. + /// + /// [`find_program_address`]: Address::find_program_address + /// + /// # Examples + /// + /// Creating a program derived address involves iteratively searching for a + /// bump seed for which the derived [`Address`] does not lie on the ed25519 + /// curve. This search process is generally performed off-chain, with the + /// [`find_program_address`] function, after which the client passes the + /// bump seed to the program as instruction data. + /// + /// Depending on the application requirements, a program may wish to verify + /// that the set of seeds, plus the bump seed, do correctly generate an + /// expected address. + /// + /// The verification is performed by appending to the other seeds one + /// additional seed slice that contains the single `u8` bump seed, calling + /// `create_program_address`, checking that the return value is `Ok`, and + /// that the returned `Address` has the expected value. + /// + /// ``` + /// # use solana_address::Address; + /// # let program_id = Address::new_unique(); + /// let (expected_pda, bump_seed) = Address::find_program_address(&[b"vault"], &program_id); + /// let actual_pda = Address::create_program_address(&[b"vault", &[bump_seed]], &program_id)?; + /// assert_eq!(expected_pda, actual_pda); + /// # Ok::<(), anyhow::Error>(()) + /// ``` + // If target_os = "solana", then the function will use + // syscalls which bring no dependencies. + // When target_os != "solana", this should be opt-in so users + // don't need the curve225519 dep. + #[cfg(any(target_os = "solana", feature = "curve25519"))] + pub fn create_program_address( + seeds: &[&[u8]], + program_id: &Address, + ) -> Result { + use crate::MAX_SEEDS; + + if seeds.len() > MAX_SEEDS { + return Err(AddressError::MaxSeedLengthExceeded); + } + for seed in seeds.iter() { + use crate::MAX_SEED_LEN; + + if seed.len() > MAX_SEED_LEN { + return Err(AddressError::MaxSeedLengthExceeded); + } + } + + // Perform the calculation inline, calling this from within a program is + // not supported + #[cfg(not(target_os = "solana"))] + { + use crate::PDA_MARKER; + + let mut hasher = solana_sha256_hasher::Hasher::default(); + for seed in seeds.iter() { + hasher.hash(seed); + } + hasher.hashv(&[program_id.as_ref(), PDA_MARKER]); + let hash = hasher.result(); + + if bytes_are_curve_point(hash) { + return Err(AddressError::InvalidSeeds); + } + + Ok(Address::from(hash.to_bytes())) + } + // Call via a system call to perform the calculation + #[cfg(target_os = "solana")] + { + let mut bytes = [0; 32]; + let result = unsafe { + crate::syscalls::sol_create_program_address( + seeds as *const _ as *const u8, + seeds.len() as u64, + program_id as *const _ as *const u8, + &mut bytes as *mut _ as *mut u8, + ) + }; + match result { + SUCCESS => Ok(Address::from(bytes)), + _ => Err(result.into()), + } + } + } +} diff --git a/atomic-u64/Cargo.toml b/atomic-u64/Cargo.toml index 548c5d486..e7591420d 100644 --- a/atomic-u64/Cargo.toml +++ b/atomic-u64/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-atomic-u64" description = "Solana atomic u64 implementation. For internal use only." documentation = "https://docs.rs/solana-atomic-u64" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/big-mod-exp/Cargo.toml b/big-mod-exp/Cargo.toml index 3cbd70115..236dd469d 100644 --- a/big-mod-exp/Cargo.toml +++ b/big-mod-exp/Cargo.toml @@ -21,9 +21,14 @@ solana-define-syscall = { workspace = true } [dev-dependencies] array-bytes = { workspace = true } +criterion = { workspace = true } serde = { workspace = true } serde_derive = { workspace = true } serde_json = { workspace = true } [lints] workspace = true + +[[bench]] +name = "big_mod_exp_bench" +harness = false diff --git a/big-mod-exp/benches/big_mod_exp_bench.rs b/big-mod-exp/benches/big_mod_exp_bench.rs new file mode 100644 index 000000000..b0021a902 --- /dev/null +++ b/big-mod-exp/benches/big_mod_exp_bench.rs @@ -0,0 +1,159 @@ +use { + criterion::{black_box, criterion_group, criterion_main, Criterion}, + serde::Deserialize, + solana_big_mod_exp::big_mod_exp, +}; + +#[derive(Deserialize, Debug)] +struct BenchmarkData { + exp_3_and_65537: BitSizeGroup, + variable_exponents: VariableBitSizeGroup, +} + +#[derive(Deserialize, Debug)] +struct BitSizeGroup { + bits_512: BaseModSet, + bits_1024: BaseModSet, + bits_2048: BaseModSet, + bits_4096: BaseModSet, +} + +#[derive(Deserialize, Debug)] +struct BaseModSet { + base: Vec, + modulus_odd: Vec, + modulus_even: Vec, +} + +#[derive(Deserialize, Debug)] +struct VariableBitSizeGroup { + bits_512: VariableSet, + bits_1024: VariableSet, + bits_2048: VariableSet, + bits_4096: VariableSet, +} + +#[derive(Deserialize, Debug)] +struct VariableSet { + base: Vec, + modulus: Vec, + exponent: Vec, +} + +fn all_benches(c: &mut Criterion) { + let data_str = include_str!("data/benchmark_constants.json"); + let data: BenchmarkData = + serde_json::from_str(data_str).expect("Failed to parse benchmark data"); + + // --- Benchmark Group for Exponent 3 --- + let mut group_exp_3 = c.benchmark_group("Exponent 3"); + let exponent_3 = [3u8]; + let const_exp_data = &data.exp_3_and_65537; + + group_exp_3.bench_function("512 bits odd", |b| { + b.iter(|| { + black_box(big_mod_exp( + &const_exp_data.bits_512.base, + &exponent_3, + &const_exp_data.bits_512.modulus_odd, + )) + }) + }); + group_exp_3.bench_function("512 bits even", |b| { + b.iter(|| { + black_box(big_mod_exp( + &const_exp_data.bits_512.base, + &exponent_3, + &const_exp_data.bits_512.modulus_even, + )) + }) + }); + group_exp_3.bench_function("1024 bits odd", |b| { + b.iter(|| { + black_box(big_mod_exp( + &const_exp_data.bits_1024.base, + &exponent_3, + &const_exp_data.bits_1024.modulus_odd, + )) + }) + }); + group_exp_3.bench_function("1024 bits even", |b| { + b.iter(|| { + black_box(big_mod_exp( + &const_exp_data.bits_1024.base, + &exponent_3, + &const_exp_data.bits_1024.modulus_even, + )) + }) + }); + group_exp_3.finish(); + + // --- Benchmark Group for Exponent 65537 --- + let mut group_exp_65537 = c.benchmark_group("Exponent 65537"); + let exponent_65537 = [1, 0, 1]; + + group_exp_65537.bench_function("2048 bits odd", |b| { + b.iter(|| { + black_box(big_mod_exp( + &const_exp_data.bits_2048.base, + &exponent_65537, + &const_exp_data.bits_2048.modulus_odd, + )) + }) + }); + group_exp_65537.bench_function("4096 bits odd", |b| { + b.iter(|| { + black_box(big_mod_exp( + &const_exp_data.bits_4096.base, + &exponent_65537, + &const_exp_data.bits_4096.modulus_odd, + )) + }) + }); + group_exp_65537.finish(); + + // --- Benchmark Group for Variable Exponents --- + let mut group_variable = c.benchmark_group("Variable Exponents"); + let var_exp_data = &data.variable_exponents; + + group_variable.bench_function("512-bit exp, 512-bit mod", |b| { + b.iter(|| { + black_box(big_mod_exp( + &var_exp_data.bits_512.base, + &var_exp_data.bits_512.exponent, + &var_exp_data.bits_512.modulus, + )) + }) + }); + group_variable.bench_function("1024-bit exp, 1024-bit mod", |b| { + b.iter(|| { + black_box(big_mod_exp( + &var_exp_data.bits_1024.base, + &var_exp_data.bits_1024.exponent, + &var_exp_data.bits_1024.modulus, + )) + }) + }); + group_variable.bench_function("2048-bit exp, 2048-bit mod", |b| { + b.iter(|| { + black_box(big_mod_exp( + &var_exp_data.bits_2048.base, + &var_exp_data.bits_2048.exponent, + &var_exp_data.bits_2048.modulus, + )) + }) + }); + group_variable.bench_function("4096-bit exp, 4096-bit mod", |b| { + b.iter(|| { + black_box(big_mod_exp( + &var_exp_data.bits_4096.base, + &var_exp_data.bits_4096.exponent, + &var_exp_data.bits_4096.modulus, + )) + }) + }); + group_variable.finish(); +} + +criterion_group!(benches, all_benches); +criterion_main!(benches); diff --git a/big-mod-exp/benches/data/benchmark_constants.json b/big-mod-exp/benches/data/benchmark_constants.json new file mode 100644 index 000000000..c8a267d09 --- /dev/null +++ b/big-mod-exp/benches/data/benchmark_constants.json @@ -0,0 +1,373 @@ +{ + "exp_3_and_65537": { + "bits_512": { + "base": [ + 243, 125, 228, 56, 107, 91, 133, 57, 46, 184, 164, 236, 176, 173, 36, 149, 58, 238, 150, + 32, 181, 248, 42, 134, 92, 170, 70, 16, 109, 212, 16, 28, 195, 174, 187, 226, 140, 22, 3, + 31, 96, 234, 110, 254, 106, 215, 101, 164, 190, 88, 14, 112, 151, 78, 205, 151, 254, 225, + 153, 125, 109, 4, 68, 87 + ], + "modulus_odd": [ + 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, + 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, + 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, + 65, 85 + ], + "modulus_even": [ + 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, + 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, + 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, + 65, 86 + ] + }, + "bits_1024": { + "base": [ + 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, + 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, + 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, + 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, + 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, + 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, + 177, 196, 122, 75, 212, 7, 183, 80, 240, 66 + ], + "modulus_odd": [ + 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, + 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, + 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, + 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, + 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, + 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, + 122, 82, 62, 74, 173, 42, 233, 38, 13, 241 + ], + "modulus_even": [ + 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, + 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, + 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, + 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, + 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, + 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, + 122, 82, 62, 74, 173, 42, 233, 38, 13, 242 + ] + }, + "bits_2048": { + "base": [ + 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, + 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, + 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, + 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, + 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, + 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, + 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, + 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, + 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, + 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, + 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, + 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, + 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, + 100, 100 + ], + "modulus_odd": [ + 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, + 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, + 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, + 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, + 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, + 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, + 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, + 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, + 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, + 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, + 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, + 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, + 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 39 + ], + "modulus_even": [ + 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, + 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, + 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, + 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, + 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, + 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, + 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, + 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, + 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, + 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, + 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, + 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, + 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 40 + ] + }, + "bits_4096": { + "base": [ + 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, + 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, + 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, + 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, + 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, + 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, + 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, + 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, + 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, + 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, + 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, + 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, + 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, + 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, + 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, + 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, + 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, + 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, + 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, + 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, + 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, + 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, + 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, + 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, + 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, + 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6 + ], + "modulus_odd": [ + 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, + 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, + 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, + 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, + 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, + 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, + 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, + 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, + 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, + 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, + 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, + 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, + 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, + 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, + 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, + 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, + 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, + 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, + 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, + 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, + 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, + 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, + 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, + 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, + 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, + 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 217 + ], + "modulus_even": [ + 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, + 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, + 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, + 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, + 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, + 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, + 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, + 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, + 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, + 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, + 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, + 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, + 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, + 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, + 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, + 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, + 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, + 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, + 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, + 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, + 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, + 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, + 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, + 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, + 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, + 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 218 + ] + } + }, + "variable_exponents": { + "bits_512": { + "base": [ + 243, 125, 228, 56, 107, 91, 133, 57, 46, 184, 164, 236, 176, 173, 36, 149, 58, 238, 150, + 32, 181, 248, 42, 134, 92, 170, 70, 16, 109, 212, 16, 28, 195, 174, 187, 226, 140, 22, 3, + 31, 96, 234, 110, 254, 106, 215, 101, 164, 190, 88, 14, 112, 151, 78, 205, 151, 254, 225, + 153, 125, 109, 4, 68, 87 + ], + "modulus": [ + 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, + 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, + 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, + 65, 85 + ], + "exponent": [ + 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, + 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, + 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, + 32, 248, 119 + ] + }, + "bits_1024": { + "base": [ + 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, + 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, + 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, + 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, + 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, + 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, + 177, 196, 122, 75, 212, 7, 183, 80, 240, 66 + ], + "modulus": [ + 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, + 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, + 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, + 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, + 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, + 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, + 122, 82, 62, 74, 173, 42, 233, 38, 13, 241 + ], + "exponent": [ + 107, 92, 159, 59, 101, 117, 205, 228, 222, 58, 188, 58, 254, 101, 230, 53, 203, 200, 138, + 56, 160, 233, 81, 218, 113, 119, 10, 214, 68, 109, 113, 15, 146, 191, 225, 80, 22, 199, + 119, 236, 23, 159, 148, 40, 113, 28, 75, 45, 15, 54, 5, 64, 103, 55, 1, 220, 236, 41, 218, + 41, 93, 6, 3, 106, 235, 31, 22, 73, 243, 113, 171, 111, 20, 237, 200, 8, 99, 252, 202, 99, + 122, 242, 84, 180, 8, 58, 3, 129, 145, 62, 179, 78, 199, 35, 212, 16, 3, 55, 9, 197, 217, + 30, 42, 67, 220, 121, 193, 16, 15, 170, 116, 65, 157, 109, 34, 211, 41, 116, 161, 40, 77, + 223, 200, 240, 31, 17, 141, 189 + ] + }, + "bits_2048": { + "base": [ + 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, + 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, + 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, + 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, + 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, + 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, + 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, + 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, + 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, + 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, + 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, + 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, + 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, + 100, 100 + ], + "modulus": [ + 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, + 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, + 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, + 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, + 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, + 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, + 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, + 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, + 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, + 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, + 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, + 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, + 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 39 + ], + "exponent": [ + 234, 85, 222, 102, 95, 165, 186, 221, 192, 109, 51, 204, 69, 225, 36, 118, 52, 132, 39, + 190, 10, 8, 82, 87, 149, 233, 35, 50, 36, 102, 243, 84, 50, 26, 54, 64, 38, 68, 154, 97, + 100, 221, 4, 81, 15, 47, 229, 100, 163, 68, 127, 163, 138, 24, 244, 125, 166, 116, 68, 126, + 201, 43, 192, 13, 236, 182, 213, 203, 235, 20, 2, 81, 168, 251, 87, 97, 69, 159, 138, 203, + 53, 43, 243, 14, 212, 5, 0, 229, 80, 72, 147, 130, 47, 13, 236, 180, 25, 100, 178, 148, + 171, 231, 252, 68, 57, 79, 14, 185, 155, 82, 103, 1, 98, 32, 204, 127, 242, 86, 25, 37, 19, + 240, 21, 64, 3, 160, 100, 76, 72, 220, 67, 123, 123, 139, 206, 75, 33, 177, 61, 129, 69, + 57, 186, 166, 3, 94, 162, 249, 22, 89, 245, 106, 180, 116, 222, 177, 231, 57, 73, 6, 217, + 252, 58, 212, 233, 219, 42, 144, 68, 92, 168, 147, 116, 82, 211, 224, 214, 156, 1, 52, 112, + 114, 193, 158, 137, 195, 46, 73, 179, 7, 229, 69, 151, 34, 78, 108, 138, 207, 37, 178, 41, + 142, 41, 163, 144, 206, 181, 71, 13, 195, 186, 74, 56, 93, 151, 97, 73, 57, 114, 198, 203, + 216, 182, 98, 88, 9, 68, 211, 235, 78, 105, 182, 245, 96, 5, 119, 229, 2, 50, 187, 159, + 131, 24, 4, 154, 234, 61, 95, 45, 102, 134, 106, 208, 39, 202, 165 + ] + }, + "bits_4096": { + "base": [ + 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, + 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, + 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, + 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, + 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, + 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, + 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, + 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, + 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, + 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, + 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, + 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, + 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, + 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, + 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, + 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, + 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, + 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, + 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, + 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, + 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, + 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, + 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, + 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, + 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, + 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6 + ], + "modulus": [ + 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, + 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, + 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, + 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, + 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, + 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, + 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, + 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, + 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, + 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, + 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, + 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, + 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, + 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, + 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, + 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, + 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, + 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, + 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, + 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, + 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, + 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, + 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, + 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, + 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, + 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 217 + ], + "exponent": [ + 160, 136, 220, 27, 39, 209, 128, 184, 213, 36, 207, 49, 210, 27, 221, 106, 122, 123, 158, + 77, 226, 64, 168, 133, 129, 82, 217, 239, 209, 235, 234, 153, 175, 4, 59, 165, 18, 109, 42, + 228, 194, 227, 131, 189, 98, 154, 242, 164, 206, 128, 151, 139, 167, 129, 179, 1, 31, 20, + 62, 168, 118, 232, 139, 241, 174, 171, 180, 238, 21, 190, 206, 250, 115, 99, 66, 152, 176, + 110, 213, 251, 176, 158, 145, 38, 61, 121, 183, 157, 18, 8, 202, 154, 26, 198, 32, 252, + 213, 40, 31, 241, 234, 13, 97, 166, 12, 199, 215, 205, 64, 121, 192, 240, 168, 241, 224, + 86, 157, 194, 1, 3, 135, 99, 201, 95, 185, 193, 142, 218, 122, 250, 84, 90, 150, 146, 2, + 173, 55, 255, 166, 150, 196, 182, 97, 4, 161, 85, 162, 74, 230, 138, 154, 128, 100, 161, + 62, 19, 74, 36, 249, 111, 45, 13, 236, 140, 73, 123, 174, 114, 45, 133, 124, 150, 15, 148, + 24, 192, 29, 116, 90, 51, 215, 62, 176, 177, 23, 211, 67, 97, 19, 231, 83, 147, 140, 99, + 186, 233, 213, 100, 109, 27, 124, 193, 193, 2, 212, 2, 55, 104, 122, 170, 249, 228, 183, + 109, 141, 58, 63, 232, 54, 255, 218, 109, 149, 174, 74, 157, 63, 252, 249, 149, 173, 28, + 249, 12, 39, 64, 90, 179, 81, 210, 129, 14, 247, 248, 169, 243, 182, 74, 143, 236, 217, + 255, 201, 184, 228, 67, 254, 115, 187, 93, 171, 34, 62, 182, 218, 0, 237, 66, 224, 51, 124, + 75, 28, 149, 207, 3, 41, 2, 113, 49, 2, 147, 227, 101, 82, 13, 120, 75, 4, 67, 244, 28, + 123, 32, 81, 32, 224, 63, 51, 62, 121, 8, 62, 234, 179, 181, 91, 76, 123, 183, 247, 135, + 40, 212, 170, 236, 45, 164, 17, 239, 65, 202, 175, 31, 116, 141, 219, 209, 253, 40, 231, + 175, 115, 59, 199, 88, 149, 101, 10, 29, 25, 233, 171, 62, 132, 90, 175, 237, 237, 167, + 153, 5, 114, 103, 227, 79, 128, 89, 207, 142, 215, 104, 92, 236, 98, 61, 187, 233, 145, + 119, 209, 100, 4, 146, 11, 247, 106, 123, 73, 200, 120, 121, 161, 118, 214, 69, 17, 66, 29, + 170, 255, 100, 59, 53, 107, 10, 231, 72, 103, 11, 223, 36, 14, 243, 252, 181, 247, 80, 253, + 110, 84, 106, 132, 102, 231, 136, 96, 148, 246, 185, 249, 207, 49, 205, 171, 168, 150, 84, + 146, 144, 228, 95, 164, 160, 194, 124, 69, 58, 168, 59, 101, 32, 196, 167, 87, 108, 99, + 126, 157, 244, 227, 224, 29, 105, 73, 249, 45, 109, 62, 180, 234, 251, 53, 11, 72, 116, 46, + 18, 102, 59, 160, 138, 22, 117, 161, 104, 189, 21, 193, 31, 175, 178, 131, 47, 127, 146, + 209, 129, 96, 61, 43, 238, 88, 211, 79, 157, 85, 15, 57, 82, 54, 104, 104, 201, 171, 60, + 26, 1, 137, 90, 234, 249 + ] + } + } +} diff --git a/big-mod-exp/src/lib.rs b/big-mod-exp/src/lib.rs index 69468545d..26edf85a6 100644 --- a/big-mod-exp/src/lib.rs +++ b/big-mod-exp/src/lib.rs @@ -71,62 +71,7 @@ mod tests { expected: String, } - let test_data = r#"[ - { - "Base": "1111111111111111111111111111111111111111111111111111111111111111", - "Exponent": "1111111111111111111111111111111111111111111111111111111111111111", - "Modulus": "111111111111111111111111111111111111111111111111111111111111110A", - "Expected": "0A7074864588D6847F33A168209E516F60005A0CEC3F33AAF70E8002FE964BCD" - }, - { - "Base": "2222222222222222222222222222222222222222222222222222222222222222", - "Exponent": "2222222222222222222222222222222222222222222222222222222222222222", - "Modulus": "1111111111111111111111111111111111111111111111111111111111111111", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000" - }, - { - "Base": "3333333333333333333333333333333333333333333333333333333333333333", - "Exponent": "3333333333333333333333333333333333333333333333333333333333333333", - "Modulus": "2222222222222222222222222222222222222222222222222222222222222222", - "Expected": "1111111111111111111111111111111111111111111111111111111111111111" - }, - { - "Base": "9874231472317432847923174392874918237439287492374932871937289719", - "Exponent": "0948403985401232889438579475812347232099080051356165126166266222", - "Modulus": "25532321a214321423124212222224222b242222222222222222222222222444", - "Expected": "220ECE1C42624E98AEE7EB86578B2FE5C4855DFFACCB43CCBB708A3AB37F184D" - }, - { - "Base": "3494396663463663636363662632666565656456646566786786676786768766", - "Exponent": "2324324333246536456354655645656616169896565698987033121934984955", - "Modulus": "0218305479243590485092843590249879879842313131156656565565656566", - "Expected": "012F2865E8B9E79B645FCE3A9E04156483AE1F9833F6BFCF86FCA38FC2D5BEF0" - }, - { - "Base": "0000000000000000000000000000000000000000000000000000000000000005", - "Exponent": "0000000000000000000000000000000000000000000000000000000000000002", - "Modulus": "0000000000000000000000000000000000000000000000000000000000000007", - "Expected": "0000000000000000000000000000000000000000000000000000000000000004" - }, - { - "Base": "0000000000000000000000000000000000000000000000000000000000000019", - "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", - "Modulus": "0000000000000000000000000000000000000000000000000000000000000064", - "Expected": "0000000000000000000000000000000000000000000000000000000000000019" - }, - { - "Base": "0000000000000000000000000000000000000000000000000000000000000019", - "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", - "Modulus": "0000000000000000000000000000000000000000000000000000000000000000", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000" - }, - { - "Base": "0000000000000000000000000000000000000000000000000000000000000019", - "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", - "Modulus": "0000000000000000000000000000000000000000000000000000000000000001", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000" - } - ]"#; + let test_data = include_str!("../tests/data/big_mod_exp_cases.json"); let test_cases: Vec = serde_json::from_str(test_data).unwrap(); test_cases.iter().for_each(|test| { diff --git a/big-mod-exp/tests/data/big_mod_exp_cases.json b/big-mod-exp/tests/data/big_mod_exp_cases.json new file mode 100644 index 000000000..cda782911 --- /dev/null +++ b/big-mod-exp/tests/data/big_mod_exp_cases.json @@ -0,0 +1,56 @@ +[ + { + "Base": "1111111111111111111111111111111111111111111111111111111111111111", + "Exponent": "1111111111111111111111111111111111111111111111111111111111111111", + "Modulus": "111111111111111111111111111111111111111111111111111111111111110A", + "Expected": "0A7074864588D6847F33A168209E516F60005A0CEC3F33AAF70E8002FE964BCD" + }, + { + "Base": "2222222222222222222222222222222222222222222222222222222222222222", + "Exponent": "2222222222222222222222222222222222222222222222222222222222222222", + "Modulus": "1111111111111111111111111111111111111111111111111111111111111111", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Base": "3333333333333333333333333333333333333333333333333333333333333333", + "Exponent": "3333333333333333333333333333333333333333333333333333333333333333", + "Modulus": "2222222222222222222222222222222222222222222222222222222222222222", + "Expected": "1111111111111111111111111111111111111111111111111111111111111111" + }, + { + "Base": "9874231472317432847923174392874918237439287492374932871937289719", + "Exponent": "0948403985401232889438579475812347232099080051356165126166266222", + "Modulus": "25532321a214321423124212222224222b242222222222222222222222222444", + "Expected": "220ECE1C42624E98AEE7EB86578B2FE5C4855DFFACCB43CCBB708A3AB37F184D" + }, + { + "Base": "3494396663463663636363662632666565656456646566786786676786768766", + "Exponent": "2324324333246536456354655645656616169896565698987033121934984955", + "Modulus": "0218305479243590485092843590249879879842313131156656565565656566", + "Expected": "012F2865E8B9E79B645FCE3A9E04156483AE1F9833F6BFCF86FCA38FC2D5BEF0" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000005", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000002", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000007", + "Expected": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000064", + "Expected": "0000000000000000000000000000000000000000000000000000000000000019" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000000", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000001", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + } +] diff --git a/bincode/Cargo.toml b/bincode/Cargo.toml index a2d55f13f..087a6bed6 100644 --- a/bincode/Cargo.toml +++ b/bincode/Cargo.toml @@ -15,9 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bincode = { workspace = true } serde = { workspace = true } -solana-instruction = { workspace = true, default-features = false, features = [ - "std", -] } +solana-instruction-error = { workspace = true } [dev-dependencies] solana-system-interface = { workspace = true, features = ["bincode"] } diff --git a/bincode/src/lib.rs b/bincode/src/lib.rs index 8170583f3..66e60a6b5 100644 --- a/bincode/src/lib.rs +++ b/bincode/src/lib.rs @@ -2,7 +2,7 @@ //! //! [bincode]: https://docs.rs/bincode -use {bincode::config::Options, solana_instruction::error::InstructionError}; +use {bincode::config::Options, solana_instruction_error::InstructionError}; /// Deserialize with a limit based the maximum amount of data a program can expect to get. /// This function should be used in place of direct deserialization to help prevent OOM errors diff --git a/blake3-hasher/Cargo.toml b/blake3-hasher/Cargo.toml index 59e969ce7..8d451945a 100644 --- a/blake3-hasher/Cargo.toml +++ b/blake3-hasher/Cargo.toml @@ -15,39 +15,19 @@ all-features = true rustdoc-args = ["--cfg=docsrs"] [features] -borsh = ["dep:borsh", "std"] -dev-context-only-utils = ["std"] -frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro", "std"] -serde = ["dep:serde", "dep:serde_derive"] blake3 = ["dep:blake3"] -std = ["solana-hash/std"] [dependencies] -borsh = { workspace = true, optional = true } -serde = { workspace = true, optional = true } -serde_derive = { workspace = true, optional = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-frozen-abi-macro = { workspace = true, optional = true, features = [ - "frozen-abi", -] } solana-hash = { workspace = true } -solana-sanitize = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] -blake3 = { workspace = true } +blake3 = { workspace = true, optional = true } [target.'cfg(target_os = "solana")'.dependencies] -# blake3 should be removed in the next breaking release, -# as there's no reason to use the crate instead of the syscall -# onchain -blake3 = { workspace = true, optional = true } solana-define-syscall = { workspace = true } [dev-dependencies] -bs58 = { workspace = true, features = ["std"] } -solana-blake3-hasher = { path = ".", features = ["dev-context-only-utils"] } +solana-blake3-hasher = { path = ".", features = ["blake3"] } [lints] workspace = true diff --git a/blake3-hasher/src/lib.rs b/blake3-hasher/src/lib.rs index a01fc6b96..da56a1710 100644 --- a/blake3-hasher/src/lib.rs +++ b/blake3-hasher/src/lib.rs @@ -2,48 +2,17 @@ //! //! [blake3]: https://github.com/BLAKE3-team/BLAKE3 #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] #![no_std] -#[cfg(feature = "std")] -extern crate std; -pub use solana_hash::{ParseHashError, HASH_BYTES, MAX_BASE58_LEN}; -#[cfg(feature = "borsh")] -use { - borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, - std::string::ToString, -}; -use { - core::{fmt, str::FromStr}, - solana_sanitize::Sanitize, -}; +pub use solana_hash::{Hash, ParseHashError, HASH_BYTES, MAX_BASE58_LEN}; -// TODO: replace this with `solana_hash::Hash` in the -// next breaking change. -// It's a breaking change because the field is public -// here and private in `solana_hash`, and making -// it public in `solana_hash` would break wasm-bindgen -#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] -#[cfg_attr( - feature = "borsh", - derive(BorshSerialize, BorshDeserialize, BorshSchema), - borsh(crate = "borsh") -)] -#[cfg_attr( - feature = "serde", - derive(serde_derive::Deserialize, serde_derive::Serialize) -)] -#[derive(Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[repr(transparent)] -pub struct Hash(pub [u8; HASH_BYTES]); - -#[cfg(any(feature = "blake3", not(target_os = "solana")))] #[derive(Clone, Default)] +#[cfg(all(feature = "blake3", not(target_os = "solana")))] pub struct Hasher { hasher: blake3::Hasher, } -#[cfg(any(feature = "blake3", not(target_os = "solana")))] +#[cfg(all(feature = "blake3", not(target_os = "solana")))] impl Hasher { pub fn hash(&mut self, val: &[u8]) { self.hasher.update(val); @@ -54,71 +23,7 @@ impl Hasher { } } pub fn result(self) -> Hash { - Hash(*self.hasher.finalize().as_bytes()) - } -} - -impl From for Hash { - fn from(val: solana_hash::Hash) -> Self { - Self(val.to_bytes()) - } -} - -impl From for solana_hash::Hash { - fn from(val: Hash) -> Self { - Self::new_from_array(val.0) - } -} - -impl Sanitize for Hash {} - -impl AsRef<[u8]> for Hash { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl fmt::Debug for Hash { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let converted: solana_hash::Hash = (*self).into(); - fmt::Debug::fmt(&converted, f) - } -} - -impl fmt::Display for Hash { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let converted: solana_hash::Hash = (*self).into(); - fmt::Display::fmt(&converted, f) - } -} - -impl FromStr for Hash { - type Err = ParseHashError; - - fn from_str(s: &str) -> Result { - let unconverted = solana_hash::Hash::from_str(s)?; - Ok(unconverted.into()) - } -} - -impl Hash { - #[deprecated(since = "2.2.0", note = "Use 'Hash::new_from_array' instead")] - pub fn new(hash_slice: &[u8]) -> Self { - #[allow(deprecated)] - Self::from(solana_hash::Hash::new(hash_slice)) - } - - pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self { - Self(hash_array) - } - - /// unique Hash for tests and benchmarks. - pub fn new_unique() -> Self { - Self::from(solana_hash::Hash::new_unique()) - } - - pub fn to_bytes(self) -> [u8; HASH_BYTES] { - self.0 + Hash::new_from_array(*self.hasher.finalize().as_bytes()) } } @@ -128,9 +33,17 @@ pub fn hashv(vals: &[&[u8]]) -> Hash { // not supported #[cfg(not(target_os = "solana"))] { - let mut hasher = Hasher::default(); - hasher.hashv(vals); - hasher.result() + #[cfg(feature = "blake3")] + { + let mut hasher = Hasher::default(); + hasher.hashv(vals); + hasher.result() + } + #[cfg(not(feature = "blake3"))] + { + core::hint::black_box(vals); + panic!("hashv is only available on target `solana` or with the `blake3` feature enabled on this crate") + } } // Call via a system call to perform the calculation #[cfg(target_os = "solana")] @@ -152,71 +65,20 @@ pub fn hash(val: &[u8]) -> Hash { hashv(&[val]) } -#[cfg(feature = "std")] -/// Return the hash of the given hash extended with the given value. -pub fn extend_and_hash(id: &Hash, val: &[u8]) -> Hash { - let mut hash_data = id.as_ref().to_vec(); - hash_data.extend_from_slice(val); - hash(&hash_data) -} - #[cfg(test)] +#[cfg(feature = "blake3")] mod tests { use super::*; #[test] - fn test_new_unique() { - assert!(Hash::new_unique() != Hash::new_unique()); - } - - #[test] - fn test_hash_fromstr() { - let hash = hash(&[1u8]); - - let mut hash_base58_str = bs58::encode(hash).into_string(); - - assert_eq!(hash_base58_str.parse::(), Ok(hash)); - - hash_base58_str.push_str(&bs58::encode(hash.0).into_string()); - assert_eq!( - hash_base58_str.parse::(), - Err(ParseHashError::WrongSize) - ); - - hash_base58_str.truncate(hash_base58_str.len() / 2); - assert_eq!(hash_base58_str.parse::(), Ok(hash)); - - hash_base58_str.truncate(hash_base58_str.len() / 2); - assert_eq!( - hash_base58_str.parse::(), - Err(ParseHashError::WrongSize) - ); - - let input_too_big = bs58::encode(&[0xffu8; HASH_BYTES + 1]).into_string(); - assert!(input_too_big.len() > MAX_BASE58_LEN); - assert_eq!( - input_too_big.parse::(), - Err(ParseHashError::WrongSize) - ); - - let mut hash_base58_str = bs58::encode(hash.0).into_string(); - assert_eq!(hash_base58_str.parse::(), Ok(hash)); - - // throw some non-base58 stuff in there - hash_base58_str.replace_range(..1, "I"); - assert_eq!( - hash_base58_str.parse::(), - Err(ParseHashError::Invalid) - ); - } - - #[test] - fn test_extend_and_hash() { + fn test_hashv() { let val = "gHiljKpq"; let val_hash = hash(val.as_bytes()); + let ext = "lM890t"; - let hash_ext = [&val_hash.0, ext.as_bytes()].concat(); - let ext_hash = extend_and_hash(&val_hash, ext.as_bytes()); + let ext_hash = hashv(&[&val_hash.to_bytes(), ext.as_bytes()]); + + let hash_ext = [&val_hash.to_bytes(), ext.as_bytes()].concat(); assert!(ext_hash == hash(&hash_ext)); } } diff --git a/bls-signatures/Cargo.toml b/bls-signatures/Cargo.toml new file mode 100644 index 000000000..5e909b0be --- /dev/null +++ b/bls-signatures/Cargo.toml @@ -0,0 +1,64 @@ +[package] +name = "solana-bls-signatures" +description = "Solana BLS Signatures" +documentation = "https://docs.rs/solana-bls-signatures" +version = "0.1.0" +rust-version = "1.81.0" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[lib] +crate-type = ["rlib"] + +[features] +bytemuck = ["dep:bytemuck"] +default = ["std"] +frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro", "std"] +parallel = ["dep:rayon"] +serde = ["dep:cfg_eval", "dep:serde", "dep:serde_with"] +solana-signer-derive = ["dep:solana-signer", "dep:solana-signature", "dep:subtle"] +std = ["dep:serde_json"] + +[dependencies] +base64 = { workspace = true } +bytemuck = { workspace = true, optional = true } +cfg_eval = { workspace = true, optional = true } +pairing = { workspace = true } +serde = { workspace = true, features = ["derive"], optional = true } +serde_json = { workspace = true, optional = true } +serde_with = { workspace = true, features = ["macros"], optional = true } +solana-frozen-abi = { workspace = true, optional = true, features = [ + "frozen-abi", +] } +solana-frozen-abi-macro = { workspace = true, optional = true, features = [ + "frozen-abi", +] } +thiserror = { workspace = true } + +[target.'cfg(not(target_os = "solana"))'.dependencies] +blst = { workspace = true } +blstrs = { workspace = true } +ff = { workspace = true } +group = { workspace = true } +rand = { workspace = true } +rayon = { workspace = true, optional = true } +solana-signature = { workspace = true, optional = true } +solana-signer = { workspace = true, optional = true } +subtle = { workspace = true, optional = true } + +[dev-dependencies] +bincode = { workspace = true } +criterion = { workspace = true } +solana-bls-signatures = { path = ".", features = ["std"] } +solana-keypair = { workspace = true } +tempfile = { workspace = true } + +[lints] +workspace = true + +[[bench]] +name = "bls_signatures" +harness = false diff --git a/bls-signatures/benches/bls_signatures.rs b/bls-signatures/benches/bls_signatures.rs new file mode 100644 index 000000000..23b161917 --- /dev/null +++ b/bls-signatures/benches/bls_signatures.rs @@ -0,0 +1,135 @@ +use { + criterion::{criterion_group, criterion_main, Criterion}, + solana_bls_signatures::{ + keypair::Keypair, + pubkey::{PubkeyProjective, VerifiablePubkey}, + signature::SignatureProjective, + }, + std::hint::black_box, +}; + +// Benchmark for verifying a single signature +fn bench_single_signature(c: &mut Criterion) { + let mut group = c.benchmark_group("single_signature"); + let keypair = Keypair::new(); + let message = b"test message"; + + group.bench_function("signature_generation", |b| { + b.iter(|| black_box(keypair.sign(message))); + }); + + let signature = keypair.sign(message); + group.bench_function("verify_signature", |b| { + b.iter(|| black_box(keypair.public.verify_signature(&signature, message)).unwrap()); + }); + group.finish(); +} + +// Worst-case benchmark for aggregate signature verification +fn bench_aggregate(c: &mut Criterion) { + let mut group = c.benchmark_group("aggregate_verify"); + // Test with a range of validator counts to simulate different scales + for num_validators in [64, 128, 256, 512, 1024, 2048].iter() { + let message = b"test message"; + let keypairs: Vec = (0..*num_validators).map(|_| Keypair::new()).collect(); + let pubkeys: Vec = keypairs.iter().map(|kp| kp.public).collect(); + let signatures: Vec = + keypairs.iter().map(|kp| kp.sign(message)).collect(); + + let pubkey_refs: Vec<&PubkeyProjective> = pubkeys.iter().collect(); + let signature_refs: Vec<&SignatureProjective> = signatures.iter().collect(); + + // Benchmark for aggregating multiple signatures + group.bench_function(format!("{num_validators} signature aggregation"), |b| { + b.iter(|| black_box(SignatureProjective::aggregate(&signature_refs))); + }); + + #[cfg(feature = "parallel")] + group.bench_function( + format!("{num_validators} parallel signature aggregation"), + |b| { + b.iter(|| black_box(SignatureProjective::par_aggregate(&signature_refs))); + }, + ); + + // Benchmark for aggregating multiple public keys + group.bench_function(format!("{num_validators} pubkey aggregation"), |b| { + b.iter(|| black_box(PubkeyProjective::aggregate(&pubkey_refs))); + }); + + // Benchmark for aggregate verify + #[cfg(feature = "parallel")] + group.bench_function( + format!("{num_validators} parallel pubkey aggregation"), + |b| { + b.iter(|| black_box(PubkeyProjective::par_aggregate(&pubkey_refs))); + }, + ); + + group.bench_function( + format!("{num_validators} sequential aggregate verification"), + |b| { + b.iter(|| { + let verification_result = black_box( + SignatureProjective::aggregate_verify( + &pubkey_refs, + &signature_refs, + message, + ) + .unwrap(), + ); + assert!(verification_result); + }); + }, + ); + + #[cfg(feature = "parallel")] + group.bench_function( + format!("{num_validators} parallel aggregate verification"), + |b| { + b.iter(|| { + let verification_result = black_box( + SignatureProjective::par_aggregate_verify( + &pubkey_refs, + &signature_refs, + message, + ) + .unwrap(), + ); + assert!(verification_result); + }); + }, + ); + } + group.finish(); +} + +// Benchmark for generating a new keypair +fn bench_key_generation(c: &mut Criterion) { + c.bench_function("key_generation", |b| b.iter(|| black_box(Keypair::new))); +} + +// Benchmark for creating and verifying a proof of possession +fn bench_proof_of_possession(c: &mut Criterion) { + let keypair = Keypair::new(); + let pop = keypair.proof_of_possession(); + + c.bench_function("proof_of_possession_creation", |b| { + b.iter(|| black_box(keypair.proof_of_possession())); + }); + + c.bench_function("proof_of_possession_verification", |b| { + b.iter(|| { + black_box(keypair.public.verify_proof_of_possession(&pop)).unwrap(); + }) + }); +} + +criterion_group!( + benches, + bench_single_signature, + bench_aggregate, + bench_key_generation, + bench_proof_of_possession +); +criterion_main!(benches); diff --git a/bls-signatures/src/error.rs b/bls-signatures/src/error.rs new file mode 100644 index 000000000..59da03395 --- /dev/null +++ b/bls-signatures/src/error.rs @@ -0,0 +1,23 @@ +use {core::convert::Infallible, thiserror::Error}; + +#[derive(Error, Clone, Debug, Eq, PartialEq)] +pub enum BlsError { + #[error("Field decode failed")] + FieldDecode, + #[error("Empty aggregation attempted")] + EmptyAggregation, + #[error("Key derivation failed")] + KeyDerivation, + #[error("Point representation conversion failed")] + PointConversion, // TODO: could be more specific here + #[error("Failed to parse from string")] + ParseFromString, // TODO: update after more precise error handling + #[error("Failed to parse from bytes")] + ParseFromBytes, +} + +impl From for BlsError { + fn from(_: Infallible) -> Self { + unreachable!() + } +} diff --git a/bls-signatures/src/hash.rs b/bls-signatures/src/hash.rs new file mode 100644 index 000000000..f4c2cc097 --- /dev/null +++ b/bls-signatures/src/hash.rs @@ -0,0 +1,21 @@ +use { + crate::{proof_of_possession::POP_DST, pubkey::PubkeyProjective}, + blstrs::G2Projective, +}; + +/// Domain separation tag used for hashing messages to curve points to prevent +/// potential conflicts between different BLS implementations. This is defined +/// as the ciphersuite ID string as recommended in the +/// [standard](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05#section-4.2.1). +pub const HASH_TO_POINT_DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"; + +/// Hash a message to a G2 point +pub fn hash_message_to_point(message: &[u8]) -> G2Projective { + G2Projective::hash_to_curve(message, HASH_TO_POINT_DST, &[]) +} + +/// Hash a pubkey to a G2 point +pub(crate) fn hash_pubkey_to_g2(public_key: &PubkeyProjective) -> G2Projective { + let pubkey_bytes = public_key.0.to_compressed(); + G2Projective::hash_to_curve(&pubkey_bytes, POP_DST, &[]) +} diff --git a/bls-signatures/src/keypair.rs b/bls-signatures/src/keypair.rs new file mode 100644 index 000000000..a6c55cba1 --- /dev/null +++ b/bls-signatures/src/keypair.rs @@ -0,0 +1,187 @@ +use crate::{ + error::BlsError, + proof_of_possession::ProofOfPossessionProjective, + pubkey::{PubkeyProjective, VerifiablePubkey, BLS_PUBLIC_KEY_AFFINE_SIZE}, + secret_key::{SecretKey, BLS_SECRET_KEY_SIZE}, + signature::{AsSignatureProjective, SignatureProjective}, +}; +#[cfg(feature = "solana-signer-derive")] +use solana_signer::Signer; +#[cfg(feature = "std")] +use std::{ + boxed::Box, + error, + fs::{self, File, OpenOptions}, + io::{Read, Write}, + path::Path, + string::String, + vec::Vec, +}; + +/// Size of BLS keypair in bytes +pub const BLS_KEYPAIR_SIZE: usize = BLS_SECRET_KEY_SIZE + BLS_PUBLIC_KEY_AFFINE_SIZE; + +/// A BLS keypair +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Keypair { + pub secret: SecretKey, + pub public: PubkeyProjective, +} + +impl Keypair { + /// Constructs a new, random `Keypair` using `OsRng` + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + let secret = SecretKey::new(); + let public = PubkeyProjective::from_secret(&secret); + Self { secret, public } + } + + /// Derive a `Keypair` from a seed (input key material) + pub fn derive(ikm: &[u8]) -> Result { + let secret = SecretKey::derive(ikm)?; + let public = PubkeyProjective::from_secret(&secret); + Ok(Self { secret, public }) + } + + /// Derive a `BlsSecretKey` from a Solana signer + #[cfg(feature = "solana-signer-derive")] + pub fn derive_from_signer(signer: &dyn Signer, public_seed: &[u8]) -> Result { + let secret = SecretKey::derive_from_signer(signer, public_seed)?; + let public = PubkeyProjective::from_secret(&secret); + Ok(Self { secret, public }) + } + + /// Generate a proof of possession for the given keypair + pub fn proof_of_possession(&self) -> ProofOfPossessionProjective { + self.secret.proof_of_possession() + } + + /// Sign a message using the provided secret key + pub fn sign(&self, message: &[u8]) -> SignatureProjective { + self.secret.sign(message) + } + + /// Verify a signature against a message and a public key + pub fn verify( + &self, + signature: &S, + message: &[u8], + ) -> Result { + self.public.verify_signature(signature, message) + } +} + +impl TryFrom<&[u8]> for Keypair { + type Error = BlsError; + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() != BLS_KEYPAIR_SIZE { + return Err(BlsError::ParseFromBytes); + } + Ok(Self { + secret: SecretKey::try_from(&bytes[..BLS_SECRET_KEY_SIZE])?, + public: PubkeyProjective::try_from(&bytes[BLS_SECRET_KEY_SIZE..])?, + }) + } +} + +impl From<&Keypair> for [u8; BLS_KEYPAIR_SIZE] { + fn from(keypair: &Keypair) -> Self { + let mut bytes = [0u8; BLS_KEYPAIR_SIZE]; + bytes[..BLS_SECRET_KEY_SIZE] + .copy_from_slice(&Into::<[u8; BLS_SECRET_KEY_SIZE]>::into(&keypair.secret)); + bytes[BLS_SECRET_KEY_SIZE..].copy_from_slice( + &Into::<[u8; BLS_PUBLIC_KEY_AFFINE_SIZE]>::into(&keypair.public), + ); + bytes + } +} + +#[cfg(feature = "std")] +impl Keypair { + pub fn read_json(reader: &mut R) -> Result> { + let bytes: Vec = serde_json::from_reader(reader)?; + Self::try_from(bytes.as_slice()) + .ok() + .ok_or_else(|| std::io::Error::other("Invalid BLS keypair").into()) + } + + pub fn read_json_file>(path: F) -> Result> { + let mut file = File::open(path.as_ref())?; + Self::read_json(&mut file) + } + + pub fn write_json(&self, writer: &mut W) -> Result> { + let json = serde_json::to_string(&Into::<[u8; BLS_KEYPAIR_SIZE]>::into(self).as_slice())?; + writer.write_all(&json.clone().into_bytes())?; + Ok(json) + } + + pub fn write_json_file>( + &self, + outfile: F, + ) -> Result> { + let outfile = outfile.as_ref(); + + if let Some(outdir) = outfile.parent() { + fs::create_dir_all(outdir)?; + } + + let mut f = { + #[cfg(not(unix))] + { + OpenOptions::new() + } + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + OpenOptions::new().mode(0o600) + } + } + .write(true) + .truncate(true) + .create(true) + .open(outfile)?; + + self.write_json(&mut f) + } +} + +#[cfg(test)] +mod tests { + use {super::*, tempfile::NamedTempFile}; + + #[test] + fn test_keygen_derive() { + let ikm = b"test_ikm"; + let secret = SecretKey::derive(ikm).unwrap(); + let public = PubkeyProjective::from_secret(&secret); + let keypair = Keypair::derive(ikm).unwrap(); + assert_eq!(keypair.secret, secret); + assert_eq!(keypair.public, public); + } + + #[test] + #[cfg(feature = "solana-signer-derive")] + fn test_keygen_derive_from_signer() { + let solana_keypair = solana_keypair::Keypair::new(); + let secret = SecretKey::derive_from_signer(&solana_keypair, b"alpenglow-vote").unwrap(); + let public = PubkeyProjective::from_secret(&secret); + let keypair = Keypair::derive_from_signer(&solana_keypair, b"alpenglow-vote").unwrap(); + + assert_eq!(keypair.secret, secret); + assert_eq!(keypair.public, public); + } + + #[test] + #[cfg(feature = "std")] + fn test_keypair_file() { + let temp_keypair_file = NamedTempFile::new().unwrap(); + let original_keypair = Keypair::new(); + original_keypair + .write_json_file(&temp_keypair_file) + .unwrap(); + let read_keypair = Keypair::read_json_file(&temp_keypair_file).unwrap(); + assert_eq!(original_keypair, read_keypair); + } +} diff --git a/bls-signatures/src/lib.rs b/bls-signatures/src/lib.rs new file mode 100644 index 000000000..2e3cb6675 --- /dev/null +++ b/bls-signatures/src/lib.rs @@ -0,0 +1,41 @@ +#![no_std] +#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] + +#[cfg(feature = "std")] +extern crate std; +#[cfg(not(target_os = "solana"))] +pub use crate::{ + error::BlsError, + keypair::Keypair, + proof_of_possession::{ + AsProofOfPossessionProjective, ProofOfPossessionProjective, VerifiableProofOfPossession, + }, + pubkey::{AsPubkeyProjective, PubkeyProjective, VerifiablePubkey}, + secret_key::{SecretKey, BLS_SECRET_KEY_SIZE}, + signature::{AsSignatureProjective, SignatureProjective, VerifiableSignature}, +}; +pub use crate::{ + proof_of_possession::{ + ProofOfPossession, ProofOfPossessionCompressed, BLS_PROOF_OF_POSSESSION_AFFINE_SIZE, + BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE, + }, + pubkey::{ + Pubkey, PubkeyCompressed, BLS_PUBLIC_KEY_AFFINE_SIZE, BLS_PUBLIC_KEY_COMPRESSED_SIZE, + }, + signature::{ + Signature, SignatureCompressed, BLS_SIGNATURE_AFFINE_SIZE, BLS_SIGNATURE_COMPRESSED_SIZE, + }, +}; + +pub mod error; +#[cfg(not(target_os = "solana"))] +pub mod keypair; +#[macro_use] +pub(crate) mod macros; +#[cfg(not(target_os = "solana"))] +pub mod hash; +pub mod proof_of_possession; +pub mod pubkey; +#[cfg(not(target_os = "solana"))] +pub mod secret_key; +pub mod signature; diff --git a/bls-signatures/src/macros.rs b/bls-signatures/src/macros.rs new file mode 100644 index 000000000..12371db8e --- /dev/null +++ b/bls-signatures/src/macros.rs @@ -0,0 +1,162 @@ +macro_rules! impl_from_str { + (TYPE = $type:ident, BYTES_LEN = $bytes_len:expr, BASE64_LEN = $base64_len:expr) => { + impl core::str::FromStr for $type { + type Err = crate::error::BlsError; + + fn from_str(s: &str) -> Result { + use base64::Engine; + + if s.len() > $base64_len { + return Err(Self::Err::ParseFromString); + } + let mut bytes = [0u8; $bytes_len]; + let decoded_len = base64::prelude::BASE64_STANDARD + .decode_slice(s, &mut bytes) + .map_err(|_| Self::Err::ParseFromString)?; + if decoded_len != $bytes_len { + Err(Self::Err::ParseFromString) + } else { + Ok($type(bytes)) + } + } + } + }; +} + +/// A macro to implement the standard set of conversions between BLS projective, +/// affine, and compressed point representations. +/// +/// # Arguments +/// +/// * `$projective`: The identifier for the projective representation struct (e.g., `PubkeyProjective`). +/// * `$affine`: The identifier for the affine (uncompressed) representation struct (e.g., `Pubkey`). +/// * `$compressed`: The identifier for the compressed representation struct (e.g., `PubkeyCompressed`). +/// * `$point_type`: The underlying `blstrs` affine point type (e.g., `G1Affine` or `G2Affine`). +/// * `$error_type`: The error type to be used for fallible conversions (e.g., `BlsError`). +/// * `$as_trait`: The identifier for the custom conversion trait (e.g., `AsPubkeyProjective`). +#[cfg(not(target_os = "solana"))] +macro_rules! impl_bls_conversions { + ( + $projective:ident, + $affine:ident, + $compressed:ident, + $point_type:ty, + $as_trait:ident + ) => { + // --- + // infallible conversions from the projective type. + // --- + impl From<&$projective> for $affine { + fn from(projective: &$projective) -> Self { + Self(projective.0.to_uncompressed()) + } + } + + impl From<$projective> for $affine { + fn from(projective: $projective) -> Self { + (&projective).into() + } + } + + // --- + // Fallible conversions from serialized types (affine, compressed) + // back to the projective type. + // --- + impl TryFrom<&$affine> for $projective { + type Error = crate::error::BlsError; + + fn try_from(affine: &$affine) -> Result { + let maybe_point: Option<$point_type> = + <$point_type>::from_uncompressed(&affine.0).into(); + let point = maybe_point.ok_or(crate::error::BlsError::PointConversion)?; + Ok(Self(point.into())) + } + } + + impl TryFrom<$affine> for $projective { + type Error = crate::error::BlsError; + + fn try_from(affine: $affine) -> Result { + Self::try_from(&affine) + } + } + + impl TryFrom<&$compressed> for $projective { + type Error = crate::error::BlsError; + + fn try_from(compressed: &$compressed) -> Result { + let maybe_point: Option<$point_type> = + <$point_type>::from_compressed(&compressed.0).into(); + let point = maybe_point.ok_or(crate::error::BlsError::PointConversion)?; + Ok(Self(point.into())) + } + } + + impl TryFrom<$compressed> for $projective { + type Error = crate::error::BlsError; + + fn try_from(compressed: $compressed) -> Result { + Self::try_from(&compressed) + } + } + + // --- + // Fallible conversions between the two serialized formats (affine and compressed). + // --- + impl TryFrom<&$affine> for $compressed { + type Error = crate::error::BlsError; + + fn try_from(affine: &$affine) -> Result { + let maybe_point: Option<$point_type> = + <$point_type>::from_uncompressed(&affine.0).into(); + let point = maybe_point.ok_or(crate::error::BlsError::PointConversion)?; + Ok(Self(point.to_compressed())) + } + } + + impl TryFrom<$affine> for $compressed { + type Error = crate::error::BlsError; + + fn try_from(affine: $affine) -> Result { + Self::try_from(&affine) + } + } + + impl TryFrom<&$compressed> for $affine { + type Error = crate::error::BlsError; + + fn try_from(compressed: &$compressed) -> Result { + let maybe_point: Option<$point_type> = + <$point_type>::from_compressed(&compressed.0).into(); + let point = maybe_point.ok_or(crate::error::BlsError::PointConversion)?; + Ok(Self(point.to_uncompressed())) + } + } + + impl TryFrom<$compressed> for $affine { + type Error = crate::error::BlsError; + + fn try_from(compressed: $compressed) -> Result { + Self::try_from(&compressed) + } + } + + impl $as_trait for $projective { + fn try_as_projective(&self) -> Result<$projective, BlsError> { + Ok(*self) + } + } + + impl $as_trait for $affine { + fn try_as_projective(&self) -> Result<$projective, BlsError> { + $projective::try_from(self) + } + } + + impl $as_trait for $compressed { + fn try_as_projective(&self) -> Result<$projective, BlsError> { + $projective::try_from(self) + } + } + }; +} diff --git a/bls-signatures/src/proof_of_possession.rs b/bls-signatures/src/proof_of_possession.rs new file mode 100644 index 000000000..179868290 --- /dev/null +++ b/bls-signatures/src/proof_of_possession.rs @@ -0,0 +1,235 @@ +#[cfg(feature = "bytemuck")] +use bytemuck::{Pod, PodInOption, Zeroable, ZeroableInOption}; +#[cfg(not(target_os = "solana"))] +use { + crate::{error::BlsError, pubkey::VerifiablePubkey}, + blstrs::{G2Affine, G2Projective}, +}; +use { + base64::{prelude::BASE64_STANDARD, Engine}, + core::fmt, +}; +#[cfg(feature = "serde")] +use { + serde::{Deserialize, Serialize}, + serde_with::serde_as, +}; + +/// Domain separation tag used when hashing public keys to G2 in the proof of +/// possession signing and verification functions. See the +/// [standard](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05#section-4.2.3). +pub const POP_DST: &[u8] = b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_POP_"; + +/// Size of a BLS proof of possession in a compressed point representation +pub const BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE: usize = 96; + +/// Size of a BLS proof of possession in a compressed point representation in base64 +pub const BLS_PROOF_OF_POSSESSION_COMPRESSED_BASE64_SIZE: usize = 128; + +/// Size of a BLS proof of possession in an affine point representation +pub const BLS_PROOF_OF_POSSESSION_AFFINE_SIZE: usize = 192; + +/// Size of a BLS proof of possession in an affine point representation in base64 +pub const BLS_PROOF_OF_POSSESSION_AFFINE_BASE64_SIZE: usize = 256; + +/// A trait for types that can be converted into a `ProofOfPossessionProjective`. +#[cfg(not(target_os = "solana"))] +pub trait AsProofOfPossessionProjective { + /// Attempt to convert the type into a `ProofOfPossessionProjective`. + fn try_as_projective(&self) -> Result; +} + +/// A trait that provides verification methods to any convertible proof of possession type. +#[cfg(not(target_os = "solana"))] +pub trait VerifiableProofOfPossession: AsProofOfPossessionProjective { + /// Verifies the proof of possession against any convertible public key type. + fn verify(&self, pubkey: &P) -> Result { + let proof_projective = self.try_as_projective()?; + pubkey.verify_proof_of_possession(&proof_projective) + } +} + +/// A BLS proof of possession in a projective point representation +#[cfg(not(target_os = "solana"))] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ProofOfPossessionProjective(pub(crate) G2Projective); + +#[cfg(not(target_os = "solana"))] +impl VerifiableProofOfPossession for T {} + +#[cfg(not(target_os = "solana"))] +impl_bls_conversions!( + ProofOfPossessionProjective, + ProofOfPossession, + ProofOfPossessionCompressed, + G2Affine, + AsProofOfPossessionProjective +); + +/// A serialized BLS signature in a compressed point representation +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct ProofOfPossessionCompressed( + #[cfg_attr( + feature = "serde", + serde_as(as = "[_; BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE]") + )] + pub [u8; BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE], +); + +impl Default for ProofOfPossessionCompressed { + fn default() -> Self { + Self([0; BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE]) + } +} + +impl fmt::Display for ProofOfPossessionCompressed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", BASE64_STANDARD.encode(self.0)) + } +} + +impl_from_str!( + TYPE = ProofOfPossessionCompressed, + BYTES_LEN = BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE, + BASE64_LEN = BLS_PROOF_OF_POSSESSION_COMPRESSED_BASE64_SIZE +); + +/// A serialized BLS signature in an affine point representation +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct ProofOfPossession( + #[cfg_attr( + feature = "serde", + serde_as(as = "[_; BLS_PROOF_OF_POSSESSION_AFFINE_SIZE]") + )] + pub [u8; BLS_PROOF_OF_POSSESSION_AFFINE_SIZE], +); + +impl Default for ProofOfPossession { + fn default() -> Self { + Self([0; BLS_PROOF_OF_POSSESSION_AFFINE_SIZE]) + } +} + +impl fmt::Display for ProofOfPossession { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", BASE64_STANDARD.encode(self.0)) + } +} + +impl_from_str!( + TYPE = ProofOfPossession, + BYTES_LEN = BLS_PROOF_OF_POSSESSION_AFFINE_SIZE, + BASE64_LEN = BLS_PROOF_OF_POSSESSION_AFFINE_BASE64_SIZE +); + +// Byte arrays are both `Pod` and `Zeraoble`, but the traits `bytemuck::Pod` and +// `bytemuck::Zeroable` can only be derived for power-of-two length byte arrays. +// Directly implement these traits for types that are simple wrappers around +// byte arrays. +#[cfg(feature = "bytemuck")] +mod bytemuck_impls { + use super::*; + + unsafe impl Zeroable for ProofOfPossessionCompressed {} + unsafe impl Pod for ProofOfPossessionCompressed {} + unsafe impl ZeroableInOption for ProofOfPossessionCompressed {} + unsafe impl PodInOption for ProofOfPossessionCompressed {} + + unsafe impl Zeroable for ProofOfPossession {} + unsafe impl Pod for ProofOfPossession {} + unsafe impl ZeroableInOption for ProofOfPossession {} + unsafe impl PodInOption for ProofOfPossession {} +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{ + keypair::Keypair, + pubkey::{Pubkey, PubkeyCompressed}, + }, + core::str::FromStr, + std::string::ToString, + }; + + #[test] + fn test_proof_of_possession() { + let keypair = Keypair::new(); + let proof_projective = keypair.proof_of_possession(); + + let pubkey_projective = keypair.public; + let pubkey_affine: Pubkey = pubkey_projective.into(); + let pubkey_compressed: PubkeyCompressed = pubkey_affine.try_into().unwrap(); + + let proof_affine: ProofOfPossession = proof_projective.into(); + let proof_compressed: ProofOfPossessionCompressed = proof_affine.try_into().unwrap(); + + assert!(proof_projective.verify(&pubkey_projective).unwrap()); + assert!(proof_affine.verify(&pubkey_projective).unwrap()); + assert!(proof_compressed.verify(&pubkey_projective).unwrap()); + + assert!(proof_projective.verify(&pubkey_affine).unwrap()); + assert!(proof_affine.verify(&pubkey_affine).unwrap()); + assert!(proof_compressed.verify(&pubkey_affine).unwrap()); + + assert!(proof_projective.verify(&pubkey_compressed).unwrap()); + assert!(proof_affine.verify(&pubkey_compressed).unwrap()); + assert!(proof_compressed.verify(&pubkey_compressed).unwrap()); + } + + #[test] + fn proof_of_possession_from_str() { + let proof_of_possession = ProofOfPossession([1; BLS_PROOF_OF_POSSESSION_AFFINE_SIZE]); + let proof_of_possession_string = proof_of_possession.to_string(); + let proof_of_possession_from_string = + ProofOfPossession::from_str(&proof_of_possession_string).unwrap(); + assert_eq!(proof_of_possession, proof_of_possession_from_string); + + let proof_of_possession_compressed = + ProofOfPossessionCompressed([1; BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE]); + let proof_of_possession_compressed_string = proof_of_possession_compressed.to_string(); + let proof_of_possession_compressed_from_string = + ProofOfPossessionCompressed::from_str(&proof_of_possession_compressed_string).unwrap(); + assert_eq!( + proof_of_possession_compressed, + proof_of_possession_compressed_from_string + ); + } + + #[cfg(feature = "serde")] + #[test] + fn serialize_and_deserialize_proof_of_possession() { + let original = ProofOfPossession::default(); + let serialized = bincode::serialize(&original).unwrap(); + let deserialized: ProofOfPossession = bincode::deserialize(&serialized).unwrap(); + assert_eq!(original, deserialized); + + let original = ProofOfPossession([1; BLS_PROOF_OF_POSSESSION_AFFINE_SIZE]); + let serialized = bincode::serialize(&original).unwrap(); + let deserialized: ProofOfPossession = bincode::deserialize(&serialized).unwrap(); + assert_eq!(original, deserialized); + } + + #[cfg(feature = "serde")] + #[test] + fn serialize_and_deserialize_proof_of_possession_compressed() { + let original = ProofOfPossessionCompressed::default(); + let serialized = bincode::serialize(&original).unwrap(); + let deserialized: ProofOfPossessionCompressed = bincode::deserialize(&serialized).unwrap(); + assert_eq!(original, deserialized); + + let original = ProofOfPossessionCompressed([1; BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE]); + let serialized = bincode::serialize(&original).unwrap(); + let deserialized: ProofOfPossessionCompressed = bincode::deserialize(&serialized).unwrap(); + assert_eq!(original, deserialized); + } +} diff --git a/bls-signatures/src/pubkey.rs b/bls-signatures/src/pubkey.rs new file mode 100644 index 000000000..dfa0ca709 --- /dev/null +++ b/bls-signatures/src/pubkey.rs @@ -0,0 +1,526 @@ +#[cfg(feature = "bytemuck")] +use bytemuck::{Pod, PodInOption, Zeroable, ZeroableInOption}; +#[cfg(all(feature = "parallel", not(target_os = "solana")))] +use rayon::prelude::*; +#[cfg(all(not(target_os = "solana"), feature = "std"))] +use std::sync::LazyLock; +#[cfg(not(target_os = "solana"))] +use { + crate::{ + error::BlsError, + hash::{hash_message_to_point, hash_pubkey_to_g2}, + proof_of_possession::{AsProofOfPossessionProjective, ProofOfPossessionProjective}, + secret_key::SecretKey, + signature::{AsSignatureProjective, SignatureProjective}, + }, + blstrs::{Bls12, G1Affine, G1Projective, G2Affine, G2Prepared, Gt}, + group::Group, + pairing::{MillerLoopResult, MultiMillerLoop}, +}; +use { + base64::{prelude::BASE64_STANDARD, Engine}, + core::fmt, +}; +#[cfg(feature = "serde")] +use { + serde::{Deserialize, Serialize}, + serde_with::serde_as, +}; + +/// Size of a BLS public key in a compressed point representation +pub const BLS_PUBLIC_KEY_COMPRESSED_SIZE: usize = 48; + +/// Size of a BLS public key in a compressed point representation in base64 +pub const BLS_PUBLIC_KEY_COMPRESSED_BASE64_SIZE: usize = 128; + +/// Size of a BLS public key in an affine point representation +pub const BLS_PUBLIC_KEY_AFFINE_SIZE: usize = 96; + +/// Size of a BLS public key in an affine point representation in base64 +pub const BLS_PUBLIC_KEY_AFFINE_BASE64_SIZE: usize = 256; + +#[cfg(all(not(target_os = "solana"), feature = "std"))] +static NEG_G1_GENERATOR_AFFINE: LazyLock = + LazyLock::new(|| (-G1Projective::generator()).into()); + +/// A trait for types that can be converted into a `PubkeyProjective`. +#[cfg(not(target_os = "solana"))] +pub trait AsPubkeyProjective { + /// Attempt to convert the type into a `PubkeyProjective`. + fn try_as_projective(&self) -> Result; +} + +/// A trait that provides verification methods to any convertible public key type. +#[cfg(not(target_os = "solana"))] +pub trait VerifiablePubkey: AsPubkeyProjective { + /// Uses this public key to verify any convertible signature type. + fn verify_signature( + &self, + signature: &S, + message: &[u8], + ) -> Result { + let pubkey_projective = self.try_as_projective()?; + let signature_projective = signature.try_as_projective()?; + Ok(pubkey_projective._verify_signature(&signature_projective, message)) + } + + /// Uses this public key to verify any convertible proof of possession type. + fn verify_proof_of_possession( + &self, + proof: &P, + ) -> Result { + let pubkey_projective = self.try_as_projective()?; + let proof_projective = proof.try_as_projective()?; + Ok(pubkey_projective._verify_proof_of_possession(&proof_projective)) + } +} + +/// A BLS public key in a projective point representation +#[cfg(not(target_os = "solana"))] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct PubkeyProjective(pub(crate) G1Projective); + +#[cfg(not(target_os = "solana"))] +impl PubkeyProjective { + /// Creates the identity element, which is the starting point for aggregation + /// + /// The identity element is not a valid public key and it should only be used + /// for the purpose of aggregation + pub fn identity() -> Self { + Self(G1Projective::identity()) + } + + /// Verify a signature and a message against a public key + pub(crate) fn _verify_signature( + &self, + signature: &SignatureProjective, + message: &[u8], + ) -> bool { + // The verification equation is e(pubkey, H(m)) = e(g1, signature). + // This can be rewritten as e(pubkey, H(m)) * e(-g1, signature) = 1, which + // allows for a more efficient verification using a multi-miller loop. + let hashed_message: G2Affine = hash_message_to_point(message).into(); + let pubkey_affine: G1Affine = self.0.into(); + let signature_affine: G2Affine = signature.0.into(); + + let hashed_message_prepared = G2Prepared::from(hashed_message); + let signature_prepared = G2Prepared::from(signature_affine); + + // use the static valud if `std` is available, otherwise compute it + #[cfg(feature = "std")] + let neg_g1_generator = &NEG_G1_GENERATOR_AFFINE; + #[cfg(not(feature = "std"))] + let neg_g1_generator_val: G1Affine = (-G1Projective::generator()).into(); + #[cfg(not(feature = "std"))] + let neg_g1_generator = &neg_g1_generator_val; + + let miller_loop_result = Bls12::multi_miller_loop(&[ + (&pubkey_affine, &hashed_message_prepared), + (neg_g1_generator, &signature_prepared), + ]); + miller_loop_result.final_exponentiation() == Gt::identity() + } + + /// Verify a proof of possession against a public key + pub(crate) fn _verify_proof_of_possession(&self, proof: &ProofOfPossessionProjective) -> bool { + // The verification equation is e(pubkey, H(pubkey)) == e(g1, proof). + // This is rewritten to e(pubkey, H(pubkey)) * e(-g1, proof) = 1 for batching. + let hashed_pubkey_affine: G2Affine = hash_pubkey_to_g2(self).into(); + let proof_affine: G2Affine = proof.0.into(); + + let pubkey_affine: G1Affine = self.0.into(); + let hashed_pubkey_prepared = G2Prepared::from(hashed_pubkey_affine); + let proof_prepared = G2Prepared::from(proof_affine); + + // Use the static value if std is available, otherwise compute it + #[cfg(feature = "std")] + let neg_g1_generator = &NEG_G1_GENERATOR_AFFINE; + #[cfg(not(feature = "std"))] + let neg_g1_generator_val: G1Affine = (-G1Projective::generator()).into(); + #[cfg(not(feature = "std"))] + let neg_g1_generator = &neg_g1_generator_val; + + let miller_loop_result = Bls12::multi_miller_loop(&[ + (&pubkey_affine, &hashed_pubkey_prepared), + // Reuse the same pre-computed static value here for efficiency + (neg_g1_generator, &proof_prepared), + ]); + + miller_loop_result.final_exponentiation() == Gt::identity() + } + + /// Construct a corresponding `BlsPubkey` for a `BlsSecretKey` + #[allow(clippy::arithmetic_side_effects)] + pub fn from_secret(secret: &SecretKey) -> Self { + Self(G1Projective::generator() * secret.0) + } + + /// Aggregate a list of public keys into an existing aggregate + #[allow(clippy::arithmetic_side_effects)] + pub fn aggregate_with( + &mut self, + pubkeys: &[&P], + ) -> Result<(), BlsError> { + for pubkey in pubkeys { + self.0 += pubkey.try_as_projective()?.0; + } + Ok(()) + } + + /// Aggregate a list of public keys + #[allow(clippy::arithmetic_side_effects)] + pub fn aggregate( + pubkeys: &[&P], + ) -> Result { + if pubkeys.is_empty() { + return Err(BlsError::EmptyAggregation); + } + if let Some((first, rest)) = pubkeys.split_first() { + let mut aggregate = first.try_as_projective()?; + aggregate.aggregate_with(rest)?; + Ok(aggregate) + } else { + Err(BlsError::EmptyAggregation) + } + } + + /// Aggregate a list of public keys into an existing aggregate + #[allow(clippy::arithmetic_side_effects)] + #[cfg(feature = "parallel")] + pub fn par_aggregate_with( + &mut self, + pubkeys: &[&P], + ) -> Result<(), BlsError> { + if pubkeys.is_empty() { + return Ok(()); + } + let aggregate = PubkeyProjective::par_aggregate(pubkeys)?; + self.0 += &aggregate.0; + Ok(()) + } + + /// Aggregate a list of public keys + #[allow(clippy::arithmetic_side_effects)] + #[cfg(feature = "parallel")] + pub fn par_aggregate( + pubkeys: &[&P], + ) -> Result { + if pubkeys.is_empty() { + return Err(BlsError::EmptyAggregation); + } + pubkeys + .into_par_iter() + .map(|key| key.try_as_projective()) + .reduce( + || Ok(PubkeyProjective::identity()), + |a, b| { + let mut a = a?; + let b = b?; + a.0 += &b.0; + Ok(a) + }, + ) + } +} + +#[cfg(not(target_os = "solana"))] +impl VerifiablePubkey for T {} + +#[cfg(not(target_os = "solana"))] +impl_bls_conversions!( + PubkeyProjective, + Pubkey, + PubkeyCompressed, + G1Affine, + AsPubkeyProjective +); + +#[cfg(not(target_os = "solana"))] +impl TryFrom<&[u8]> for PubkeyProjective { + type Error = BlsError; + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() != BLS_PUBLIC_KEY_AFFINE_SIZE { + return Err(BlsError::ParseFromBytes); + } + // unwrap safe due to the length check above + let public_affine = Pubkey(bytes.try_into().unwrap()); + + public_affine.try_into() + } +} + +#[cfg(not(target_os = "solana"))] +impl From<&PubkeyProjective> for [u8; BLS_PUBLIC_KEY_AFFINE_SIZE] { + fn from(pubkey: &PubkeyProjective) -> Self { + let pubkey_affine: Pubkey = (*pubkey).into(); + pubkey_affine.0 + } +} + +/// A serialized BLS public key in a compressed point representation +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct PubkeyCompressed( + #[cfg_attr( + feature = "serde", + serde_as(as = "[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]") + )] + pub [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE], +); + +impl Default for PubkeyCompressed { + fn default() -> Self { + Self([0; BLS_PUBLIC_KEY_COMPRESSED_SIZE]) + } +} + +impl fmt::Display for PubkeyCompressed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", BASE64_STANDARD.encode(self.0)) + } +} + +impl_from_str!( + TYPE = PubkeyCompressed, + BYTES_LEN = BLS_PUBLIC_KEY_COMPRESSED_SIZE, + BASE64_LEN = BLS_PUBLIC_KEY_COMPRESSED_BASE64_SIZE +); + +/// A serialized BLS public key in an affine point representation +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Pubkey( + #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_PUBLIC_KEY_AFFINE_SIZE]"))] + pub [u8; BLS_PUBLIC_KEY_AFFINE_SIZE], +); + +impl Default for Pubkey { + fn default() -> Self { + Self([0; BLS_PUBLIC_KEY_AFFINE_SIZE]) + } +} + +impl fmt::Display for Pubkey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", BASE64_STANDARD.encode(self.0)) + } +} + +impl_from_str!( + TYPE = Pubkey, + BYTES_LEN = BLS_PUBLIC_KEY_AFFINE_SIZE, + BASE64_LEN = BLS_PUBLIC_KEY_AFFINE_BASE64_SIZE +); + +// Byte arrays are both `Pod` and `Zeraoble`, but the traits `bytemuck::Pod` and +// `bytemuck::Zeroable` can only be derived for power-of-two length byte arrays. +// Directly implement these traits for types that are simple wrappers around +// byte arrays. +#[cfg(feature = "bytemuck")] +mod bytemuck_impls { + use super::*; + unsafe impl Zeroable for PubkeyCompressed {} + unsafe impl Pod for PubkeyCompressed {} + unsafe impl ZeroableInOption for PubkeyCompressed {} + unsafe impl PodInOption for PubkeyCompressed {} + + unsafe impl Zeroable for Pubkey {} + unsafe impl Pod for Pubkey {} + unsafe impl ZeroableInOption for Pubkey {} + unsafe impl PodInOption for Pubkey {} +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{ + keypair::Keypair, + proof_of_possession::{ProofOfPossession, ProofOfPossessionCompressed}, + signature::{Signature, SignatureCompressed}, + }, + core::str::FromStr, + std::string::ToString, + }; + + #[test] + fn test_pubkey_verify_signature() { + let keypair = Keypair::new(); + let test_message = b"test message"; + let signature_projective = keypair.sign(test_message); + + let pubkey_projective = keypair.public; + let pubkey_affine: Pubkey = pubkey_projective.into(); + let pubkey_compressed: PubkeyCompressed = pubkey_affine.try_into().unwrap(); + + let signature_affine: Signature = signature_projective.into(); + let signature_compressed: SignatureCompressed = signature_affine.try_into().unwrap(); + + assert!(pubkey_projective + .verify_signature(&signature_projective, test_message) + .unwrap()); + assert!(pubkey_affine + .verify_signature(&signature_projective, test_message) + .unwrap()); + assert!(pubkey_compressed + .verify_signature(&signature_projective, test_message) + .unwrap()); + + assert!(pubkey_projective + .verify_signature(&signature_affine, test_message) + .unwrap()); + assert!(pubkey_affine + .verify_signature(&signature_affine, test_message) + .unwrap()); + assert!(pubkey_compressed + .verify_signature(&signature_affine, test_message) + .unwrap()); + + assert!(pubkey_projective + .verify_signature(&signature_compressed, test_message) + .unwrap()); + assert!(pubkey_affine + .verify_signature(&signature_compressed, test_message) + .unwrap()); + assert!(pubkey_compressed + .verify_signature(&signature_compressed, test_message) + .unwrap()); + } + + #[test] + fn test_pubkey_verify_proof_of_possession() { + let keypair = Keypair::new(); + let proof_projective = keypair.proof_of_possession(); + + let pubkey_projective = keypair.public; + let pubkey_affine: Pubkey = pubkey_projective.into(); + let pubkey_compressed: PubkeyCompressed = pubkey_affine.try_into().unwrap(); + + let proof_affine: ProofOfPossession = proof_projective.into(); + let proof_compressed: ProofOfPossessionCompressed = proof_affine.try_into().unwrap(); + + assert!(pubkey_projective + .verify_proof_of_possession(&proof_projective) + .unwrap()); + assert!(pubkey_affine + .verify_proof_of_possession(&proof_projective) + .unwrap()); + assert!(pubkey_compressed + .verify_proof_of_possession(&proof_projective) + .unwrap()); + + assert!(pubkey_projective + .verify_proof_of_possession(&proof_affine) + .unwrap()); + assert!(pubkey_affine + .verify_proof_of_possession(&proof_affine) + .unwrap()); + assert!(pubkey_compressed + .verify_proof_of_possession(&proof_affine) + .unwrap()); + + assert!(pubkey_projective + .verify_proof_of_possession(&proof_compressed) + .unwrap()); + assert!(pubkey_affine + .verify_proof_of_possession(&proof_compressed) + .unwrap()); + assert!(pubkey_compressed + .verify_proof_of_possession(&proof_compressed) + .unwrap()); + } + + #[test] + fn test_pubkey_aggregate_dyn() { + let keypair0 = Keypair::new(); + let keypair1 = Keypair::new(); + + let pubkey_projective = keypair0.public; + let pubkey_affine: Pubkey = keypair1.public.into(); + let pubkey_compressed: PubkeyCompressed = Pubkey::from(keypair1.public).try_into().unwrap(); + + let dyn_pubkeys: std::vec::Vec<&dyn AsPubkeyProjective> = + std::vec![&pubkey_projective, &pubkey_affine, &pubkey_compressed]; + + let aggregate_from_dyn = PubkeyProjective::aggregate(&dyn_pubkeys).unwrap(); + let pubkeys_for_baseline = [&keypair0.public, &keypair1.public, &keypair1.public]; + let baseline_aggregate = PubkeyProjective::aggregate(&pubkeys_for_baseline).unwrap(); + + assert_eq!(aggregate_from_dyn, baseline_aggregate); + } + + #[test] + fn pubkey_from_str() { + let pubkey = Keypair::new().public; + let pubkey_affine: Pubkey = pubkey.into(); + let pubkey_affine_string = pubkey_affine.to_string(); + let pubkey_affine_from_string = Pubkey::from_str(&pubkey_affine_string).unwrap(); + assert_eq!(pubkey_affine, pubkey_affine_from_string); + + let pubkey_compressed = PubkeyCompressed([1; BLS_PUBLIC_KEY_COMPRESSED_SIZE]); + let pubkey_compressed_string = pubkey_compressed.to_string(); + let pubkey_compressed_from_string = + PubkeyCompressed::from_str(&pubkey_compressed_string).unwrap(); + assert_eq!(pubkey_compressed, pubkey_compressed_from_string); + } + + #[cfg(feature = "serde")] + #[test] + fn serialize_and_deserialize_pubkey() { + let original = Pubkey::default(); + let serialized = bincode::serialize(&original).unwrap(); + let deserialized: Pubkey = bincode::deserialize(&serialized).unwrap(); + assert_eq!(original, deserialized); + + let original = Pubkey([1; BLS_PUBLIC_KEY_AFFINE_SIZE]); + let serialized = bincode::serialize(&original).unwrap(); + let deserialized: Pubkey = bincode::deserialize(&serialized).unwrap(); + assert_eq!(original, deserialized); + } + + #[cfg(feature = "serde")] + #[test] + fn serialize_and_deserialize_pubkey_compressed() { + let original = PubkeyCompressed::default(); + let serialized = bincode::serialize(&original).unwrap(); + let deserialized: PubkeyCompressed = bincode::deserialize(&serialized).unwrap(); + assert_eq!(original, deserialized); + + let original = PubkeyCompressed([1; BLS_PUBLIC_KEY_COMPRESSED_SIZE]); + let serialized = bincode::serialize(&original).unwrap(); + let deserialized: PubkeyCompressed = bincode::deserialize(&serialized).unwrap(); + assert_eq!(original, deserialized); + } + + #[test] + #[cfg(feature = "parallel")] + fn test_parallel_pubkey_aggregation() { + let keypair0 = Keypair::new(); + let keypair1 = Keypair::new(); + let pubkey0 = keypair0.public; + let pubkey1 = keypair1.public; + + // Test `aggregate` + let sequential_agg = PubkeyProjective::aggregate(&[&pubkey0, &pubkey1]).unwrap(); + let parallel_agg = PubkeyProjective::par_aggregate(&[&pubkey0, &pubkey1]).unwrap(); + assert_eq!(sequential_agg, parallel_agg); + + // Test `aggregate_with` + let mut parallel_agg_with = pubkey0; + parallel_agg_with.par_aggregate_with(&[&pubkey1]).unwrap(); + assert_eq!(sequential_agg, parallel_agg_with); + + // Test empty case + let empty_slice: &[&PubkeyProjective] = &[]; + assert_eq!( + PubkeyProjective::par_aggregate(empty_slice).unwrap_err(), + BlsError::EmptyAggregation + ); + } +} diff --git a/bls-signatures/src/secret_key.rs b/bls-signatures/src/secret_key.rs new file mode 100644 index 000000000..789cd6129 --- /dev/null +++ b/bls-signatures/src/secret_key.rs @@ -0,0 +1,100 @@ +use { + crate::{ + error::BlsError, + hash::{hash_message_to_point, hash_pubkey_to_g2}, + proof_of_possession::ProofOfPossessionProjective, + pubkey::PubkeyProjective, + signature::SignatureProjective, + }, + blst::{blst_keygen, blst_scalar}, + blstrs::Scalar, + core::ptr, + ff::Field, + rand::rngs::OsRng, +}; +#[cfg(feature = "solana-signer-derive")] +use {solana_signature::Signature, solana_signer::Signer, subtle::ConstantTimeEq}; + +/// Size of BLS secret key in bytes +pub const BLS_SECRET_KEY_SIZE: usize = 32; + +/// A BLS secret key +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SecretKey(pub(crate) Scalar); + +impl SecretKey { + /// Constructs a new, random `BlsSecretKey` using `OsRng` + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + let mut rng = OsRng; + Self(Scalar::random(&mut rng)) + } + + /// Derive a `BlsSecretKey` from a seed (input key material) + pub fn derive(ikm: &[u8]) -> Result { + let mut scalar = blst_scalar::default(); + unsafe { + blst_keygen( + &mut scalar as *mut blst_scalar, + ikm.as_ptr(), + ikm.len(), + ptr::null(), + 0, + ); + } + scalar + .try_into() + .map(Self) + .map_err(|_| BlsError::FieldDecode) + } + + /// Derive a `BlsSecretKey` from a Solana signer + #[cfg(feature = "solana-signer-derive")] + pub fn derive_from_signer(signer: &dyn Signer, public_seed: &[u8]) -> Result { + let message = [b"bls-key-derive-", public_seed].concat(); + let signature = signer + .try_sign_message(&message) + .map_err(|_| BlsError::KeyDerivation)?; + + // Some `Signer` implementations return the default signature, which is not suitable for + // use as key material + if bool::from(signature.as_ref().ct_eq(Signature::default().as_ref())) { + return Err(BlsError::KeyDerivation); + } + + Self::derive(signature.as_ref()) + } + + /// Generate a proof of possession for the corresponding pubkey + #[allow(clippy::arithmetic_side_effects)] + pub fn proof_of_possession(&self) -> ProofOfPossessionProjective { + let pubkey = PubkeyProjective::from_secret(self); + let hashed_pubkey_bytes = hash_pubkey_to_g2(&pubkey); + ProofOfPossessionProjective(hashed_pubkey_bytes * self.0) + } + + /// Sign a message using the provided secret key + #[allow(clippy::arithmetic_side_effects)] + pub fn sign(&self, message: &[u8]) -> SignatureProjective { + let hashed_message = hash_message_to_point(message); + SignatureProjective(hashed_message * self.0) + } +} + +impl TryFrom<&[u8]> for SecretKey { + type Error = BlsError; + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() != BLS_SECRET_KEY_SIZE { + return Err(BlsError::ParseFromBytes); + } + // unwrap safe due to the length check above + let scalar: Option = Scalar::from_bytes_le(bytes.try_into().unwrap()).into(); + scalar.ok_or(BlsError::FieldDecode).map(Self) + } +} + +impl From<&SecretKey> for [u8; BLS_SECRET_KEY_SIZE] { + fn from(secret_key: &SecretKey) -> Self { + secret_key.0.to_bytes_le() + } +} diff --git a/bls-signatures/src/signature.rs b/bls-signatures/src/signature.rs new file mode 100644 index 000000000..2d3d50b1b --- /dev/null +++ b/bls-signatures/src/signature.rs @@ -0,0 +1,524 @@ +#[cfg(feature = "bytemuck")] +use bytemuck::{Pod, PodInOption, Zeroable, ZeroableInOption}; +#[cfg(all(feature = "parallel", not(target_os = "solana")))] +use rayon::prelude::*; +#[cfg(not(target_os = "solana"))] +use { + crate::{ + error::BlsError, + pubkey::{AsPubkeyProjective, PubkeyProjective, VerifiablePubkey}, + }, + blstrs::{G2Affine, G2Projective}, + group::Group, +}; +use { + base64::{prelude::BASE64_STANDARD, Engine}, + core::fmt, +}; +#[cfg(feature = "serde")] +use { + serde::{Deserialize, Serialize}, + serde_with::serde_as, +}; + +/// Size of a BLS signature in a compressed point representation +pub const BLS_SIGNATURE_COMPRESSED_SIZE: usize = 96; + +/// Size of a BLS signature in a compressed point representation in base64 +pub const BLS_SIGNATURE_COMPRESSED_BASE64_SIZE: usize = 128; + +/// Size of a BLS signature in an affine point representation +pub const BLS_SIGNATURE_AFFINE_SIZE: usize = 192; + +/// Size of a BLS signature in an affine point representation in base64 +pub const BLS_SIGNATURE_AFFINE_BASE64_SIZE: usize = 256; + +/// A trait for types that can be converted into a `SignatureProjective`. +#[cfg(not(target_os = "solana"))] +pub trait AsSignatureProjective { + /// Attempt to convert the type into a `SignatureProjective`. + fn try_as_projective(&self) -> Result; +} + +/// A trait that provides verification methods to any convertible signature type. +#[cfg(not(target_os = "solana"))] +pub trait VerifiableSignature: AsSignatureProjective { + /// Verify the signature against any convertible public key type and a message. + fn verify(&self, pubkey: &P, message: &[u8]) -> Result { + // The logic is defined once here. + let signature_projective = self.try_as_projective()?; + pubkey.verify_signature(&signature_projective, message) + } +} + +/// A BLS signature in a projective point representation +#[cfg(not(target_os = "solana"))] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct SignatureProjective(pub(crate) G2Projective); + +#[cfg(not(target_os = "solana"))] +impl SignatureProjective { + /// Creates the identity element, which is the starting point for aggregation + /// + /// The identity element is not a valid signature and it should only be used + /// for the purpose of aggregation + pub fn identity() -> Self { + Self(G2Projective::identity()) + } + + /// Aggregate a list of signatures into an existing aggregate + #[allow(clippy::arithmetic_side_effects)] + pub fn aggregate_with( + &mut self, + signatures: &[&S], + ) -> Result<(), BlsError> { + for signature in signatures { + self.0 += signature.try_as_projective()?.0; + } + Ok(()) + } + + /// Aggregate a list of signatures + #[allow(clippy::arithmetic_side_effects)] + pub fn aggregate( + signatures: &[&S], + ) -> Result { + if let Some((first, rest)) = signatures.split_first() { + let mut aggregate = first.try_as_projective()?; + aggregate.aggregate_with(rest)?; + Ok(aggregate) + } else { + Err(BlsError::EmptyAggregation) + } + } + + /// Verify a list of signatures against a message and a list of public keys + pub fn aggregate_verify( + public_keys: &[&P], + signatures: &[&S], + message: &[u8], + ) -> Result { + let aggregate_pubkey = PubkeyProjective::aggregate(public_keys)?; + let aggregate_signature = SignatureProjective::aggregate(signatures)?; + + Ok(aggregate_pubkey._verify_signature(&aggregate_signature, message)) + } + + /// Aggregate a list of signatures into an existing aggregate + #[allow(clippy::arithmetic_side_effects)] + #[cfg(feature = "parallel")] + pub fn par_aggregate_with( + &mut self, + signatures: &[&S], + ) -> Result<(), BlsError> { + let aggregate = SignatureProjective::par_aggregate(signatures)?; + self.0 += &aggregate.0; + Ok(()) + } + + /// Aggregate a list of signatures + #[allow(clippy::arithmetic_side_effects)] + #[cfg(feature = "parallel")] + pub fn par_aggregate( + signatures: &[&S], + ) -> Result { + if signatures.is_empty() { + return Err(BlsError::EmptyAggregation); + } + signatures + .into_par_iter() + .map(|sig| (*sig).try_as_projective()) + .reduce( + || Ok(SignatureProjective::identity()), + |a, b| { + let mut a = a?; + let b = b?; + a.0 += &b.0; + Ok(a) + }, + ) + } + + /// Verify a list of signatures against a message and a list of public keys + #[cfg(feature = "parallel")] + pub fn par_aggregate_verify( + public_keys: &[&P], + signatures: &[&S], + message: &[u8], + ) -> Result { + let (aggregate_pubkey_res, aggregate_signature_res) = rayon::join( + || PubkeyProjective::par_aggregate(public_keys), + || SignatureProjective::par_aggregate(signatures), + ); + let aggregate_pubkey = aggregate_pubkey_res?; + let aggregate_signature = aggregate_signature_res?; + Ok(aggregate_pubkey._verify_signature(&aggregate_signature, message)) + } +} + +#[cfg(not(target_os = "solana"))] +impl VerifiableSignature for T {} + +#[cfg(not(target_os = "solana"))] +impl_bls_conversions!( + SignatureProjective, + Signature, + SignatureCompressed, + G2Affine, + AsSignatureProjective +); + +/// A serialized BLS signature in a compressed point representation +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct SignatureCompressed( + #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_SIGNATURE_COMPRESSED_SIZE]"))] + pub [u8; BLS_SIGNATURE_COMPRESSED_SIZE], +); + +impl Default for SignatureCompressed { + fn default() -> Self { + Self([0; BLS_SIGNATURE_COMPRESSED_SIZE]) + } +} + +impl fmt::Display for SignatureCompressed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", BASE64_STANDARD.encode(self.0)) + } +} + +impl_from_str!( + TYPE = SignatureCompressed, + BYTES_LEN = BLS_SIGNATURE_COMPRESSED_SIZE, + BASE64_LEN = BLS_SIGNATURE_COMPRESSED_BASE64_SIZE +); + +/// A serialized BLS signature in an affine point representation +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Signature( + #[cfg_attr(feature = "serde", serde_as(as = "[_; BLS_SIGNATURE_AFFINE_SIZE]"))] + pub [u8; BLS_SIGNATURE_AFFINE_SIZE], +); + +impl Default for Signature { + fn default() -> Self { + Self([0; BLS_SIGNATURE_AFFINE_SIZE]) + } +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", BASE64_STANDARD.encode(self.0)) + } +} + +impl_from_str!( + TYPE = Signature, + BYTES_LEN = BLS_SIGNATURE_AFFINE_SIZE, + BASE64_LEN = BLS_SIGNATURE_AFFINE_BASE64_SIZE +); + +// Byte arrays are both `Pod` and `Zeraoble`, but the traits `bytemuck::Pod` and +// `bytemuck::Zeroable` can only be derived for power-of-two length byte arrays. +// Directly implement these traits for types that are simple wrappers around +// byte arrays. +#[cfg(feature = "bytemuck")] +mod bytemuck_impls { + use super::*; + + unsafe impl Zeroable for Signature {} + unsafe impl Pod for Signature {} + unsafe impl ZeroableInOption for Signature {} + unsafe impl PodInOption for Signature {} + + unsafe impl Zeroable for SignatureCompressed {} + unsafe impl Pod for SignatureCompressed {} + unsafe impl ZeroableInOption for SignatureCompressed {} + unsafe impl PodInOption for SignatureCompressed {} +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{ + keypair::Keypair, + pubkey::{Pubkey, PubkeyCompressed}, + }, + core::str::FromStr, + std::{string::ToString, vec::Vec}, + }; + + #[test] + fn test_signature_verification() { + let keypair = Keypair::new(); + let test_message = b"test message"; + let signature_projective = keypair.sign(test_message); + + let pubkey_projective = keypair.public; + let pubkey_affine: Pubkey = pubkey_projective.into(); + let pubkey_compressed: PubkeyCompressed = pubkey_affine.try_into().unwrap(); + + let signature_affine: Signature = signature_projective.into(); + let signature_compressed: SignatureCompressed = signature_affine.try_into().unwrap(); + + assert!(signature_projective + .verify(&pubkey_projective, test_message) + .unwrap()); + assert!(signature_affine + .verify(&pubkey_projective, test_message) + .unwrap()); + assert!(signature_compressed + .verify(&pubkey_projective, test_message) + .unwrap()); + + assert!(signature_projective + .verify(&pubkey_affine, test_message) + .unwrap()); + assert!(signature_affine + .verify(&pubkey_affine, test_message) + .unwrap()); + assert!(signature_compressed + .verify(&pubkey_affine, test_message) + .unwrap()); + + assert!(signature_projective + .verify(&pubkey_compressed, test_message) + .unwrap()); + assert!(signature_affine + .verify(&pubkey_compressed, test_message) + .unwrap()); + assert!(signature_compressed + .verify(&pubkey_compressed, test_message) + .unwrap()); + } + + #[test] + fn test_signature_aggregate() { + let test_message = b"test message"; + let keypair0 = Keypair::new(); + let signature0 = keypair0.sign(test_message); + + let test_message = b"test message"; + let keypair1 = Keypair::new(); + let signature1 = keypair1.sign(test_message); + let signature1_affine: Signature = signature1.into(); + + let aggregate_signature = + SignatureProjective::aggregate(&[&signature0, &signature1]).unwrap(); + + let mut aggregate_signature_with = signature0; + aggregate_signature_with + .aggregate_with(&[&signature1_affine]) + .unwrap(); + + assert_eq!(aggregate_signature, aggregate_signature_with); + } + + #[test] + fn test_aggregate_verify() { + let test_message = b"test message"; + + let keypair0 = Keypair::new(); + let signature0 = keypair0.sign(test_message); + assert!(keypair0 + .public + .verify_signature(&signature0, test_message) + .unwrap()); + + let keypair1 = Keypair::new(); + let signature1 = keypair1.secret.sign(test_message); + assert!(keypair1 + .public + .verify_signature(&signature1, test_message) + .unwrap()); + + // basic case + assert!(SignatureProjective::aggregate_verify( + &[&keypair0.public, &keypair1.public], + &[&signature0, &signature1], + test_message, + ) + .unwrap()); + + // verify with affine and compressed types + let pubkey0_affine: Pubkey = keypair0.public.into(); + let pubkey1_affine: Pubkey = keypair1.public.into(); + let signature0_affine: Signature = signature0.into(); + let signature1_affine: Signature = signature1.into(); + assert!(SignatureProjective::aggregate_verify( + &[&pubkey0_affine, &pubkey1_affine], + &[&signature0_affine, &signature1_affine], + test_message, + ) + .unwrap()); + + // pre-aggregate the signatures + let aggregate_signature = + SignatureProjective::aggregate(&[&signature0, &signature1]).unwrap(); + assert!(SignatureProjective::aggregate_verify( + &[&keypair0.public, &keypair1.public], + &[&aggregate_signature], + test_message, + ) + .unwrap()); + + // pre-aggregate the public keys + let aggregate_pubkey = + PubkeyProjective::aggregate(&[&keypair0.public, &keypair1.public]).unwrap(); + assert!(SignatureProjective::aggregate_verify( + &[&aggregate_pubkey], + &[&signature0, &signature1], + test_message, + ) + .unwrap()); + + // empty set of public keys or signatures + let err = SignatureProjective::aggregate_verify( + &[] as &[&PubkeyProjective], + &[&signature0, &signature1], + test_message, + ) + .unwrap_err(); + assert_eq!(err, BlsError::EmptyAggregation); + + let err = SignatureProjective::aggregate_verify( + &[&keypair0.public, &keypair1.public], + &[] as &[&SignatureProjective], + test_message, + ) + .unwrap_err(); + assert_eq!(err, BlsError::EmptyAggregation); + } + + #[test] + fn test_aggregate_verify_dyn() { + let test_message = b"test message for dyn verify"; + + let keypair0 = Keypair::new(); + let keypair1 = Keypair::new(); + let keypair2 = Keypair::new(); + + let signature0_projective = keypair0.sign(test_message); + let signature1_projective = keypair1.sign(test_message); + let signature2_projective = keypair2.sign(test_message); + + let pubkey0 = keypair0.public; // Projective + let pubkey1_affine: Pubkey = keypair1.public.into(); // Affine + let pubkey2_compressed: PubkeyCompressed = + Pubkey::from(keypair2.public).try_into().unwrap(); // Compressed + + let signature0 = signature0_projective; // Projective + let signature1_affine: Signature = signature1_projective.into(); // Affine + let signature2_compressed: SignatureCompressed = + Signature::from(signature2_projective).try_into().unwrap(); // Compressed + + let dyn_pubkeys: Vec<&dyn AsPubkeyProjective> = + std::vec![&pubkey0, &pubkey1_affine, &pubkey2_compressed]; + let dyn_signatures: Vec<&dyn AsSignatureProjective> = + std::vec![&signature0, &signature1_affine, &signature2_compressed]; + + assert!( + SignatureProjective::aggregate_verify(&dyn_pubkeys, &dyn_signatures, test_message) + .unwrap() + ); + + let wrong_message = b"this is not the correct message"; + let dyn_pubkeys_fail: Vec<&dyn AsPubkeyProjective> = + std::vec![&pubkey0, &pubkey1_affine, &pubkey2_compressed]; + let dyn_signatures_fail: Vec<&dyn AsSignatureProjective> = + std::vec![&signature0, &signature1_affine, &signature2_compressed]; + assert!(!SignatureProjective::aggregate_verify( + &dyn_pubkeys_fail, + &dyn_signatures_fail, + wrong_message + ) + .unwrap()); + } + + #[test] + fn signature_from_str() { + let signature_affine = Signature([1; BLS_SIGNATURE_AFFINE_SIZE]); + let signature_affine_string = signature_affine.to_string(); + let signature_affine_from_string = Signature::from_str(&signature_affine_string).unwrap(); + assert_eq!(signature_affine, signature_affine_from_string); + + let signature_compressed = SignatureCompressed([1; BLS_SIGNATURE_COMPRESSED_SIZE]); + let signature_compressed_string = signature_compressed.to_string(); + let signature_compressed_from_string = + SignatureCompressed::from_str(&signature_compressed_string).unwrap(); + assert_eq!(signature_compressed, signature_compressed_from_string); + } + + #[test] + #[cfg(feature = "parallel")] + fn test_parallel_signature_aggregation() { + let keypair0 = Keypair::new(); + let keypair1 = Keypair::new(); + let signature0 = keypair0.sign(b""); + let signature1 = keypair1.sign(b""); + + // Test `aggregate` + let sequential_agg = SignatureProjective::aggregate(&[&signature0, &signature1]).unwrap(); + let parallel_agg = SignatureProjective::par_aggregate(&[&signature0, &signature1]).unwrap(); + assert_eq!(sequential_agg, parallel_agg); + + // Test `aggregate_with` + let mut parallel_agg_with = signature0; + parallel_agg_with + .par_aggregate_with(&[&signature1]) + .unwrap(); + assert_eq!(sequential_agg, parallel_agg_with); + + // Test empty case + let empty_slice: &[&SignatureProjective] = &[]; + assert_eq!( + SignatureProjective::par_aggregate(empty_slice).unwrap_err(), + BlsError::EmptyAggregation + ); + } + + #[test] + #[cfg(feature = "parallel")] + fn test_parallel_aggregate_verify() { + let message = b"test message"; + let keypairs: Vec<_> = (0..5).map(|_| Keypair::new()).collect(); + let pubkeys: Vec<_> = keypairs.iter().map(|kp| kp.public).collect(); + let pubkey_refs: Vec<_> = pubkeys.iter().collect(); + let signatures: Vec<_> = keypairs.iter().map(|kp| kp.sign(message)).collect(); + let signature_refs: Vec<_> = signatures.iter().collect(); + + // Success case + assert!( + SignatureProjective::par_aggregate_verify(&pubkey_refs, &signature_refs, message) + .unwrap() + ); + + // Failure case (wrong message) + assert!(!SignatureProjective::par_aggregate_verify( + &pubkey_refs, + &signature_refs, + b"wrong message" + ) + .unwrap()); + + // Failure case (bad signature) + let mut bad_signatures = signatures.clone(); + bad_signatures[0] = keypairs[0].sign(b"a different message"); + let bad_signature_refs: Vec<_> = bad_signatures.iter().collect(); + assert!(!SignatureProjective::par_aggregate_verify( + &pubkey_refs, + &bad_signature_refs, + message + ) + .unwrap()); + } +} diff --git a/bn254/Cargo.toml b/bn254/Cargo.toml index ad132b4b7..5ed445319 100644 --- a/bn254/Cargo.toml +++ b/bn254/Cargo.toml @@ -12,7 +12,6 @@ include = ["src/**/*"] [dependencies] bytemuck = { workspace = true, features = ["derive"] } -solana-define-syscall = { workspace = true } thiserror = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] @@ -21,6 +20,9 @@ ark-ec = { workspace = true } ark-ff = { workspace = true } ark-serialize = { workspace = true } +[target.'cfg(target_os = "solana")'.dependencies] +solana-define-syscall = { workspace = true } + [dev-dependencies] array-bytes = { workspace = true } criterion = { workspace = true } diff --git a/bn254/src/compression.rs b/bn254/src/compression.rs index 883dd3901..5dbbbefd7 100644 --- a/bn254/src/compression.rs +++ b/bn254/src/compression.rs @@ -387,108 +387,4 @@ mod tests { let g1_decompressed = alt_bn128_g2_decompress(&g1_compressed).unwrap(); assert_eq!(g1_bytes, g1_decompressed); } - #[test] - fn alt_bn128_compression_pairing_test_input() { - use serde_derive::Deserialize; - - let test_data = r#"[ - { - "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff1", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff2", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff3", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff4", - "Gas": 147000, - "NoBenchmark": false - },{ - "Input": "20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff5", - "Gas": 147000, - "NoBenchmark": false - },{ - "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000", - "Name": "jeff6", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000", - "Name": "one_point", - "Gas": 79000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "two_point_match_2", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "two_point_match_3", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "two_point_match_4", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "ten_point_match_1", - "Gas": 385000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "ten_point_match_2", - "Gas": 385000, - "NoBenchmark": false - },{ - "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "ten_point_match_3", - "Gas": 113000, - "NoBenchmark": false - } - ]"#; - - #[derive(Deserialize)] - #[serde(rename_all = "PascalCase")] - struct TestCase { - input: String, - } - - let test_cases: Vec = serde_json::from_str(test_data).unwrap(); - - test_cases.iter().for_each(|test| { - let input = array_bytes::hex2bytes_unchecked(&test.input); - let g1 = input[0..64].to_vec(); - let g1_compressed = alt_bn128_g1_compress(&g1).unwrap(); - assert_eq!(g1, alt_bn128_g1_decompress(&g1_compressed).unwrap()); - let g2 = input[64..192].to_vec(); - let g2_compressed = alt_bn128_g2_compress(&g2).unwrap(); - assert_eq!(g2, alt_bn128_g2_decompress(&g2_compressed).unwrap()); - }); - } } diff --git a/bn254/src/lib.rs b/bn254/src/lib.rs index 1b68af9cd..1a861fc49 100644 --- a/bn254/src/lib.rs +++ b/bn254/src/lib.rs @@ -469,344 +469,6 @@ mod tests { assert_eq!(p, zero); } - #[test] - fn alt_bn128_addition_test() { - use serde_derive::Deserialize; - - let test_data = r#"[ - { - "Input": "18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726607c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7", - "Expected": "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915", - "Name": "chfast1", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c91518b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266", - "Expected": "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204", - "Name": "chfast2", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Name": "cdetrio1", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Name": "cdetrio2", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Name": "cdetrio3", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "", - "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Name": "cdetrio4", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", - "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", - "Name": "cdetrio5", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", - "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", - "Name": "cdetrio6", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", - "Gas": 150, - "Name": "cdetrio7", - "NoBenchmark": false - },{ - "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", - "Expected": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", - "Name": "cdetrio8", - "Gas": 150, - "NoBenchmark": false - },{ - "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", - "Expected": "15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f", - "Name": "cdetrio9", - "Gas": 150, - "NoBenchmark": false - } - ]"#; - - #[derive(Deserialize)] - #[serde(rename_all = "PascalCase")] - struct TestCase { - input: String, - expected: String, - } - - let test_cases: Vec = serde_json::from_str(test_data).unwrap(); - - test_cases.iter().for_each(|test| { - let input = array_bytes::hex2bytes_unchecked(&test.input); - let result = alt_bn128_addition(&input); - assert!(result.is_ok()); - - let expected = array_bytes::hex2bytes_unchecked(&test.expected); - - assert_eq!(result.unwrap(), expected); - }); - } - - #[test] - fn alt_bn128_multiplication_test() { - use serde_derive::Deserialize; - - let test_data = r#"[ - { - "Input": "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20400000000000000000000000000000000000000000000000011138ce750fa15c2", - "Expected": "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc", - "Name": "chfast1", - "Gas": 6000, - "NoBenchmark": false - },{ - "Input": "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46", - "Expected": "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e", - "Name": "chfast2", - "Gas": 6000, - "NoBenchmark": false - },{ - "Input": "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3", - "Expected": "14789d0d4a730b354403b5fac948113739e276c23e0258d8596ee72f9cd9d3230af18a63153e0ec25ff9f2951dd3fa90ed0197bfef6e2a1a62b5095b9d2b4a27", - "Name": "chfast3", - "Gas": 6000, - "NoBenchmark": false - },{ - "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "Expected": "2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11", - "Name": "cdetrio1", - "Gas": 6000, - "NoBenchmark": false - },{ - "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", - "Expected": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451", - "Name": "cdetrio2", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000100000000000000000000000000000000", - "Expected": "1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b", - "Name": "cdetrio3", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000009", - "Expected": "1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575", - "Name": "cdetrio4", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000001", - "Expected": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6", - "Name": "cdetrio5", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "Expected": "29e587aadd7c06722aabba753017c093f70ba7eb1f1c0104ec0564e7e3e21f6022b1143f6a41008e7755c71c3d00b6b915d386de21783ef590486d8afa8453b1", - "Name": "cdetrio6", - "Gas": 6000, - "NoBenchmark": false - },{ - "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", - "Expected": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb", - "Name": "cdetrio7", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000100000000000000000000000000000000", - "Expected": "221a3577763877920d0d14a91cd59b9479f83b87a653bb41f82a3f6f120cea7c2752c7f64cdd7f0e494bff7b60419f242210f2026ed2ec70f89f78a4c56a1f15", - "Name": "cdetrio8", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000009", - "Expected": "228e687a379ba154554040f8821f4e41ee2be287c201aa9c3bc02c9dd12f1e691e0fd6ee672d04cfd924ed8fdc7ba5f2d06c53c1edc30f65f2af5a5b97f0a76a", - "Name": "cdetrio9", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000001", - "Expected": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c", - "Name": "cdetrio10", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "Expected": "00a1a234d08efaa2616607e31eca1980128b00b415c845ff25bba3afcb81dc00242077290ed33906aeb8e42fd98c41bcb9057ba03421af3f2d08cfc441186024", - "Name": "cdetrio11", - "Gas": 6000, - "NoBenchmark": false - },{ - "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d9830644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", - "Expected": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b8692929ee761a352600f54921df9bf472e66217e7bb0cee9032e00acc86b3c8bfaf", - "Name": "cdetrio12", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000100000000000000000000000000000000", - "Expected": "1071b63011e8c222c5a771dfa03c2e11aac9666dd097f2c620852c3951a4376a2f46fe2f73e1cf310a168d56baa5575a8319389d7bfa6b29ee2d908305791434", - "Name": "cdetrio13", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000009", - "Expected": "19f75b9dd68c080a688774a6213f131e3052bd353a304a189d7a2ee367e3c2582612f545fb9fc89fde80fd81c68fc7dcb27fea5fc124eeda69433cf5c46d2d7f", - "Name": "cdetrio14", - "Gas": 6000, - "NoBenchmark": true - },{ - "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000001", - "Expected": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", - "Name": "cdetrio15", - "Gas": 6000, - "NoBenchmark": true - } - ]"#; - - #[derive(Deserialize)] - #[serde(rename_all = "PascalCase")] - struct TestCase { - input: String, - expected: String, - } - - let test_cases: Vec = serde_json::from_str(test_data).unwrap(); - - test_cases.iter().for_each(|test| { - let input = array_bytes::hex2bytes_unchecked(&test.input); - let result = alt_bn128_multiplication(&input); - assert!(result.is_ok()); - let expected = array_bytes::hex2bytes_unchecked(&test.expected); - assert_eq!(result.unwrap(), expected); - }); - } - - #[test] - fn alt_bn128_pairing_test() { - use serde_derive::Deserialize; - - let test_data = r#"[ - { - "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff1", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff2", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff3", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff4", - "Gas": 147000, - "NoBenchmark": false - },{ - "Input": "20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "jeff5", - "Gas": 147000, - "NoBenchmark": false - },{ - "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000", - "Name": "jeff6", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "empty_data", - "Gas": 45000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000000", - "Name": "one_point", - "Gas": 79000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "two_point_match_2", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "two_point_match_3", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "two_point_match_4", - "Gas": 113000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "ten_point_match_1", - "Gas": 385000, - "NoBenchmark": false - },{ - "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "ten_point_match_2", - "Gas": 385000, - "NoBenchmark": false - },{ - "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", - "Expected": "0000000000000000000000000000000000000000000000000000000000000001", - "Name": "ten_point_match_3", - "Gas": 113000, - "NoBenchmark": false - } - ]"#; - - #[derive(Deserialize)] - #[serde(rename_all = "PascalCase")] - struct TestCase { - input: String, - expected: String, - } - - let test_cases: Vec = serde_json::from_str(test_data).unwrap(); - - test_cases.iter().for_each(|test| { - let input = array_bytes::hex2bytes_unchecked(&test.input); - let result = alt_bn128_pairing(&input); - assert!(result.is_ok()); - let expected = array_bytes::hex2bytes_unchecked(&test.expected); - assert_eq!(result.unwrap(), expected); - }); - } - #[test] fn alt_bn128_pairing_invalid_length() { use ark_ff::{BigInteger, BigInteger256}; diff --git a/bn254/tests/curve_operations.rs b/bn254/tests/curve_operations.rs new file mode 100644 index 000000000..b3d0bcbb8 --- /dev/null +++ b/bn254/tests/curve_operations.rs @@ -0,0 +1,101 @@ +use { + serde_derive::Deserialize, + solana_bn254::{compression::prelude::*, prelude::*}, +}; + +#[test] +fn alt_bn128_addition_test() { + let test_data = include_str!("data/addition_cases.json"); + + #[derive(Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + input: String, + expected: String, + } + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + + test_cases.iter().for_each(|test| { + let input = array_bytes::hex2bytes_unchecked(&test.input); + let result = alt_bn128_addition(&input); + assert!(result.is_ok()); + let expected = array_bytes::hex2bytes_unchecked(&test.expected); + assert_eq!(result.unwrap(), expected); + }); +} + +#[test] +fn alt_bn128_multiplication_test() { + let test_data = include_str!("data/multiplication_cases.json"); + #[derive(Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + input: String, + expected: String, + } + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + + test_cases.iter().for_each(|test| { + let input = array_bytes::hex2bytes_unchecked(&test.input); + let result = alt_bn128_multiplication(&input); + assert!(result.is_ok()); + let expected = array_bytes::hex2bytes_unchecked(&test.expected); + assert_eq!(result.unwrap(), expected); + }); +} + +#[test] +fn alt_bn128_pairing_test() { + let test_data = include_str!("data/pairing_cases.json"); + + #[derive(Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + input: String, + expected: String, + } + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + + test_cases.iter().for_each(|test| { + let input = array_bytes::hex2bytes_unchecked(&test.input); + let result = alt_bn128_pairing(&input); + assert!(result.is_ok()); + let expected = array_bytes::hex2bytes_unchecked(&test.expected); + assert_eq!(result.unwrap(), expected); + }); +} + +// This test validates the compression and decompression roundtrip logic. +#[test] +fn alt_bn128_compression_pairing_test_input() { + let test_data = include_str!("data/pairing_cases.json"); + + #[derive(Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + input: String, + } + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + + test_cases.iter().for_each(|test| { + let input = array_bytes::hex2bytes_unchecked(&test.input); + + // This test reuses data from the pairing test suite, which can include + // inputs too short for this test's logic (e.g. the "empty" test case). + // We skip those cases to prevent a panic when slicing the input bytes + // for the G1 and G2 points. + if input.len() < 192 { + return; + } + let g1 = input[0..64].to_vec(); + let g1_compressed = alt_bn128_g1_compress(&g1).unwrap(); + assert_eq!(g1, alt_bn128_g1_decompress(&g1_compressed).unwrap()); + let g2 = input[64..192].to_vec(); + let g2_compressed = alt_bn128_g2_compress(&g2).unwrap(); + assert_eq!(g2, alt_bn128_g2_decompress(&g2_compressed).unwrap()); + }); +} diff --git a/bn254/tests/data/addition_cases.json b/bn254/tests/data/addition_cases.json new file mode 100644 index 000000000..5defee055 --- /dev/null +++ b/bn254/tests/data/addition_cases.json @@ -0,0 +1,79 @@ +[ + { + "Input": "18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726607c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7", + "Expected": "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915", + "Name": "chfast1", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c91518b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266", + "Expected": "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204", + "Name": "chfast2", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio1", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio2", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio3", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio4", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Name": "cdetrio5", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Name": "cdetrio6", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Name": "cdetrio7", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Expected": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "Name": "cdetrio8", + "Gas": 150, + "NoBenchmark": false + }, + { + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + "Expected": "15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f", + "Name": "cdetrio9", + "Gas": 150, + "NoBenchmark": false + } +] diff --git a/bn254/tests/data/multiplication_cases.json b/bn254/tests/data/multiplication_cases.json new file mode 100644 index 000000000..318125df1 --- /dev/null +++ b/bn254/tests/data/multiplication_cases.json @@ -0,0 +1,128 @@ +[ + { + "Input": "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20400000000000000000000000000000000000000000000000011138ce750fa15c2", + "Expected": "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc", + "Name": "chfast1", + "Gas": 6000, + "NoBenchmark": false + }, + { + "Input": "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46", + "Expected": "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e", + "Name": "chfast2", + "Gas": 6000, + "NoBenchmark": false + }, + { + "Input": "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3", + "Expected": "14789d0d4a730b354403b5fac948113739e276c23e0258d8596ee72f9cd9d3230af18a63153e0ec25ff9f2951dd3fa90ed0197bfef6e2a1a62b5095b9d2b4a27", + "Name": "chfast3", + "Gas": 6000, + "NoBenchmark": false + }, + { + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "Expected": "2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11", + "Name": "cdetrio1", + "Gas": 6000, + "NoBenchmark": false + }, + { + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + "Expected": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451", + "Name": "cdetrio2", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000100000000000000000000000000000000", + "Expected": "1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b", + "Name": "cdetrio3", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000009", + "Expected": "1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575", + "Name": "cdetrio4", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000001", + "Expected": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6", + "Name": "cdetrio5", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "Expected": "29e587aadd7c06722aabba753017c093f70ba7eb1f1c0104ec0564e7e3e21f6022b1143f6a41008e7755c71c3d00b6b915d386de21783ef590486d8afa8453b1", + "Name": "cdetrio6", + "Gas": 6000, + "NoBenchmark": false + }, + { + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + "Expected": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb", + "Name": "cdetrio7", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000100000000000000000000000000000000", + "Expected": "221a3577763877920d0d14a91cd59b9479f83b87a653bb41f82a3f6f120cea7c2752c7f64cdd7f0e494bff7b60419f242210f2026ed2ec70f89f78a4c56a1f15", + "Name": "cdetrio8", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000009", + "Expected": "228e687a379ba154554040f8821f4e41ee2be287c201aa9c3bc02c9dd12f1e691e0fd6ee672d04cfd924ed8fdc7ba5f2d06c53c1edc30f65f2af5a5b97f0a76a", + "Name": "cdetrio9", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000001", + "Expected": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c", + "Name": "cdetrio10", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "Expected": "00a1a234d08efaa2616607e31eca1980128b00b415c845ff25bba3afcb81dc00242077290ed33906aeb8e42fd98c41bcb9057ba03421af3f2d08cfc441186024", + "Name": "cdetrio11", + "Gas": 6000, + "NoBenchmark": false + }, + { + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d9830644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + "Expected": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b8692929ee761a352600f54921df9bf472e66217e7bb0cee9032e00acc86b3c8bfaf", + "Name": "cdetrio12", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000100000000000000000000000000000000", + "Expected": "1071b63011e8c222c5a771dfa03c2e11aac9666dd097f2c620852c3951a4376a2f46fe2f73e1cf310a168d56baa5575a8319389d7bfa6b29ee2d908305791434", + "Name": "cdetrio13", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000009", + "Expected": "19f75b9dd68c080a688774a6213f131e3052bd353a304a189d7a2ee367e3c2582612f545fb9fc89fde80fd81c68fc7dcb27fea5fc124eeda69433cf5c46d2d7f", + "Name": "cdetrio14", + "Gas": 6000, + "NoBenchmark": true + }, + { + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000001", + "Expected": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + "Name": "cdetrio15", + "Gas": 6000, + "NoBenchmark": true + } +] diff --git a/bn254/tests/data/pairing_cases.json b/bn254/tests/data/pairing_cases.json new file mode 100644 index 000000000..37ec3569f --- /dev/null +++ b/bn254/tests/data/pairing_cases.json @@ -0,0 +1,100 @@ +[ + { + "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff1", + "Gas": 113000, + "NoBenchmark": false + }, + { + "Input": "2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff2", + "Gas": 113000, + "NoBenchmark": false + }, + { + "Input": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff3", + "Gas": 113000, + "NoBenchmark": false + }, + { + "Input": "2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff4", + "Gas": 147000, + "NoBenchmark": false + }, + { + "Input": "20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff5", + "Gas": 147000, + "NoBenchmark": false + }, + { + "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000", + "Name": "jeff6", + "Gas": 113000, + "NoBenchmark": false + }, + { + "Input": "", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "empty_data", + "Gas": 45000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000", + "Name": "one_point", + "Gas": 79000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "two_point_match_2", + "Gas": 113000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "two_point_match_3", + "Gas": 113000, + "NoBenchmark": false + }, + { + "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "two_point_match_4", + "Gas": 113000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "ten_point_match_1", + "Gas": 385000, + "NoBenchmark": false + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "ten_point_match_2", + "Gas": 385000, + "NoBenchmark": false + }, + { + "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "ten_point_match_3", + "Gas": 113000, + "NoBenchmark": false + } +] diff --git a/borsh/Cargo.toml b/borsh/Cargo.toml index 1a25cc7c1..eb360482b 100644 --- a/borsh/Cargo.toml +++ b/borsh/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-borsh" description = "Solana Borsh utilities" documentation = "https://docs.rs/solana-borsh" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -14,7 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] borsh = { workspace = true } -borsh0-10 = { workspace = true } [lints] workspace = true diff --git a/borsh/src/deprecated.rs b/borsh/src/deprecated.rs deleted file mode 100644 index 9bf34f017..000000000 --- a/borsh/src/deprecated.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Utilities for the [borsh] serialization format. -//! -//! To avoid backwards-incompatibilities when the Solana SDK changes its dependency -//! on borsh, it's recommended to instead use the version-specific file directly, -//! ie. `v0_10`. -//! -//! This file remains for developers who use these borsh helpers, but it will -//! be removed in a future release -//! -//! [borsh]: https://borsh.io/ -use borsh0_10::{maybestd::io::Error, BorshDeserialize, BorshSchema, BorshSerialize}; - -/// Get the worst-case packed length for the given BorshSchema -/// -/// Note: due to the serializer currently used by Borsh, this function cannot -/// be used on-chain in the Solana SBF execution environment. -#[deprecated(since = "1.17.0", note = "Please use `v0_10::get_packed_len` instead")] -pub fn get_packed_len() -> usize { - #[allow(deprecated)] - crate::v0_10::get_packed_len::() -} - -/// Deserializes without checking that the entire slice has been consumed -/// -/// Normally, `try_from_slice` checks the length of the final slice to ensure -/// that the deserialization uses up all of the bytes in the slice. -/// -/// Note that there is a potential issue with this function. Any buffer greater than -/// or equal to the expected size will properly deserialize. For example, if the -/// user passes a buffer destined for a different type, the error won't get caught -/// as easily. -#[deprecated( - since = "1.17.0", - note = "Please use `v0_10::try_from_slice_unchecked` instead" -)] -pub fn try_from_slice_unchecked(data: &[u8]) -> Result { - #[allow(deprecated)] - crate::v0_10::try_from_slice_unchecked::(data) -} - -/// Get the packed length for the serialized form of this object instance. -/// -/// Useful when working with instances of types that contain a variable-length -/// sequence, such as a Vec or HashMap. Since it is impossible to know the packed -/// length only from the type's schema, this can be used when an instance already -/// exists, to figure out how much space to allocate in an account. -#[deprecated( - since = "1.17.0", - note = "Please use `v0_10::get_instance_packed_len` instead" -)] -pub fn get_instance_packed_len(instance: &T) -> Result { - #[allow(deprecated)] - crate::v0_10::get_instance_packed_len(instance) -} diff --git a/borsh/src/lib.rs b/borsh/src/lib.rs index d0ca1d3fe..ac5203ff2 100644 --- a/borsh/src/lib.rs +++ b/borsh/src/lib.rs @@ -1,4 +1,2 @@ -pub mod deprecated; pub mod macros; -pub mod v0_10; pub mod v1; diff --git a/borsh/src/macros.rs b/borsh/src/macros.rs index 8d5ab7532..be13471f4 100644 --- a/borsh/src/macros.rs +++ b/borsh/src/macros.rs @@ -1,67 +1,5 @@ //! Macros for implementing functions across multiple versions of Borsh -macro_rules! impl_get_packed_len_v0 { - ($borsh:ident $(,#[$meta:meta])?) => { - /// Get the worst-case packed length for the given BorshSchema - /// - /// Note: due to the serializer currently used by Borsh, this function cannot - /// be used on-chain in the Solana SBF execution environment. - $(#[$meta])? - pub fn get_packed_len() -> usize { - let $borsh::schema::BorshSchemaContainer { declaration, definitions } = - &S::schema_container(); - get_declaration_packed_len(declaration, definitions) - } - - /// Get packed length for the given BorshSchema Declaration - fn get_declaration_packed_len( - declaration: &str, - definitions: &std::collections::HashMap<$borsh::schema::Declaration, $borsh::schema::Definition>, - ) -> usize { - match definitions.get(declaration) { - Some($borsh::schema::Definition::Array { length, elements }) => { - *length as usize * get_declaration_packed_len(elements, definitions) - } - Some($borsh::schema::Definition::Enum { variants }) => { - 1 + variants - .iter() - .map(|(_, declaration)| get_declaration_packed_len(declaration, definitions)) - .max() - .unwrap_or(0) - } - Some($borsh::schema::Definition::Struct { fields }) => match fields { - $borsh::schema::Fields::NamedFields(named_fields) => named_fields - .iter() - .map(|(_, declaration)| get_declaration_packed_len(declaration, definitions)) - .sum(), - $borsh::schema::Fields::UnnamedFields(declarations) => declarations - .iter() - .map(|declaration| get_declaration_packed_len(declaration, definitions)) - .sum(), - $borsh::schema::Fields::Empty => 0, - }, - Some($borsh::schema::Definition::Sequence { - elements: _elements, - }) => panic!("Missing support for Definition::Sequence"), - Some($borsh::schema::Definition::Tuple { elements }) => elements - .iter() - .map(|element| get_declaration_packed_len(element, definitions)) - .sum(), - None => match declaration { - "bool" | "u8" | "i8" => 1, - "u16" | "i16" => 2, - "u32" | "i32" => 4, - "u64" | "i64" => 8, - "u128" | "i128" => 16, - "nil" => 0, - _ => panic!("Missing primitive type: {declaration}"), - }, - } - } - } -} -pub(crate) use impl_get_packed_len_v0; - macro_rules! impl_get_packed_len_v1 { ($borsh:ident $(,#[$meta:meta])?) => { /// Get the worst-case packed length for the given BorshSchema diff --git a/borsh/src/v0_10.rs b/borsh/src/v0_10.rs deleted file mode 100644 index b709cc83a..000000000 --- a/borsh/src/v0_10.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![allow(clippy::arithmetic_side_effects)] -//! Utilities for the [borsh] serialization format, version 0.10. -//! -//! [borsh]: https://borsh.io/ -use { - crate::macros::{ - impl_get_instance_packed_len, impl_get_packed_len_v0, impl_try_from_slice_unchecked, - }, - borsh0_10::maybestd::io, -}; - -impl_get_packed_len_v0!( - borsh0_10, - #[deprecated( - since = "1.18.0", - note = "Please upgrade to Borsh 1.X and use `v1::get_packed_len` instead" - )] -); -impl_try_from_slice_unchecked!( - borsh0_10, - io, - #[deprecated( - since = "1.18.0", - note = "Please upgrade to Borsh 1.X and use `v1::try_from_slice_unchecked` instead" - )] -); -impl_get_instance_packed_len!( - borsh0_10, - io, - #[deprecated( - since = "1.18.0", - note = "Please upgrade to Borsh 1.X and use `v1::get_instance_packed_len` instead" - )] -); - -#[cfg(test)] -#[allow(deprecated)] -mod tests { - use {crate::macros::impl_tests, borsh0_10::maybestd::io}; - impl_tests!(borsh0_10, io); -} diff --git a/client-traits/Cargo.toml b/client-traits/Cargo.toml index a1edbf483..5b60c4bbb 100644 --- a/client-traits/Cargo.toml +++ b/client-traits/Cargo.toml @@ -23,6 +23,6 @@ solana-message = { workspace = true } solana-pubkey = { workspace = true } solana-signature = { workspace = true } solana-signer = { workspace = true } -solana-system-interface = { workspace = true } +solana-system-interface = { workspace = true, features = ["bincode"] } solana-transaction = { workspace = true, features = ["bincode"] } solana-transaction-error = { workspace = true } diff --git a/clock/src/lib.rs b/clock/src/lib.rs index 8596923d7..f263a7853 100644 --- a/clock/src/lib.rs +++ b/clock/src/lib.rs @@ -46,48 +46,10 @@ pub const DEFAULT_TICKS_PER_SLOT: u64 = 64; pub const DEFAULT_HASHES_PER_SECOND: u64 = 10_000_000; -// Empirical sampling of mainnet validator hash rate showed the following stake -// percentages can exceed the designated hash rates as of July 2023: -// 97.6% -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_SECOND' instead")] -pub const UPDATED_HASHES_PER_SECOND_2: u64 = 2_800_000; -// 96.2% -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_SECOND' instead")] -pub const UPDATED_HASHES_PER_SECOND_3: u64 = 4_400_000; -// 96.2% -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_SECOND' instead")] -pub const UPDATED_HASHES_PER_SECOND_4: u64 = 7_600_000; -// 96.2% -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_SECOND' instead")] -pub const UPDATED_HASHES_PER_SECOND_5: u64 = 9_200_000; -// 96.2% -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_SECOND' instead")] -pub const UPDATED_HASHES_PER_SECOND_6: u64 = 10_000_000; - #[cfg(test)] static_assertions::const_assert_eq!(DEFAULT_HASHES_PER_TICK, 62_500); pub const DEFAULT_HASHES_PER_TICK: u64 = DEFAULT_HASHES_PER_SECOND / DEFAULT_TICKS_PER_SECOND; -#[cfg(test)] -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_TICK' instead")] -pub const UPDATED_HASHES_PER_TICK2: u64 = DEFAULT_HASHES_PER_SECOND / DEFAULT_TICKS_PER_SECOND; - -#[cfg(test)] -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_TICK' instead")] -pub const UPDATED_HASHES_PER_TICK3: u64 = DEFAULT_HASHES_PER_SECOND / DEFAULT_TICKS_PER_SECOND; - -#[cfg(test)] -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_TICK' instead")] -pub const UPDATED_HASHES_PER_TICK4: u64 = DEFAULT_HASHES_PER_SECOND / DEFAULT_TICKS_PER_SECOND; - -#[cfg(test)] -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_TICK' instead")] -pub const UPDATED_HASHES_PER_TICK5: u64 = DEFAULT_HASHES_PER_SECOND / DEFAULT_TICKS_PER_SECOND; - -#[cfg(test)] -#[deprecated(since = "2.2.2", note = "Use 'DEFAULT_HASHES_PER_TICK' instead")] -pub const UPDATED_HASHES_PER_TICK6: u64 = DEFAULT_HASHES_PER_SECOND / DEFAULT_TICKS_PER_SECOND; - // 1 Dev Epoch = 400 ms * 8192 ~= 55 minutes pub const DEFAULT_DEV_SLOTS_PER_EPOCH: u64 = 8192; diff --git a/commitment-config/Cargo.toml b/commitment-config/Cargo.toml index cba27c057..e1e6d0941 100644 --- a/commitment-config/Cargo.toml +++ b/commitment-config/Cargo.toml @@ -2,7 +2,8 @@ name = "solana-commitment-config" description = "Solana commitment config." documentation = "https://docs.rs/solana-commitment-config" -version = "2.2.1" +version = "3.0.0" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/commitment-config/src/lib.rs b/commitment-config/src/lib.rs index 2048a6ba7..c80df086a 100644 --- a/commitment-config/src/lib.rs +++ b/commitment-config/src/lib.rs @@ -54,14 +54,6 @@ impl CommitmentConfig { pub fn is_at_least_confirmed(&self) -> bool { self.is_confirmed() || self.is_finalized() } - - #[deprecated( - since = "2.0.2", - note = "Returns self. Please do not use. Will be removed in the future." - )] - pub fn use_deprecated_commitment(commitment: CommitmentConfig) -> Self { - commitment - } } impl FromStr for CommitmentConfig { @@ -134,7 +126,7 @@ pub enum ParseCommitmentLevelError { Invalid, } -impl std::error::Error for ParseCommitmentLevelError {} +impl core::error::Error for ParseCommitmentLevelError {} impl fmt::Display for ParseCommitmentLevelError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/cpi/Cargo.toml b/cpi/Cargo.toml index dcdd67133..1e4679788 100644 --- a/cpi/Cargo.toml +++ b/cpi/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] solana-account-info = { workspace = true } -solana-instruction = { workspace = true } +solana-instruction = { workspace = true, features = ["std"] } solana-program-error = { workspace = true } solana-pubkey = { workspace = true } diff --git a/decode-error/Cargo.toml b/decode-error/Cargo.toml deleted file mode 100644 index d2ffbce28..000000000 --- a/decode-error/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "solana-decode-error" -description = "Solana DecodeError Trait" -documentation = "https://docs.rs/solana-decode-error" -version = "2.3.0" -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -license = { workspace = true } -edition = { workspace = true } - -[dependencies] -num-traits = { workspace = true } - -[dev-dependencies] -num-derive = { workspace = true } diff --git a/decode-error/src/lib.rs b/decode-error/src/lib.rs deleted file mode 100644 index 77bbdee6c..000000000 --- a/decode-error/src/lib.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Converting custom error codes to enums. - -use num_traits::FromPrimitive; - -/// Allows custom errors to be decoded back to their original enum. -/// -/// Some Solana error enums, like [`ProgramError`], include a `Custom` variant, -/// like [`ProgramError::Custom`], that contains a `u32` error code. This code -/// may represent any error that is not covered by the error enum's named -/// variants. It is common for programs to convert their own error enums to an -/// error code and store it in the `Custom` variant, possibly with the help of -/// the [`ToPrimitive`] trait. -/// -/// This trait builds on the [`FromPrimitive`] trait to help convert those error -/// codes to the original error enum they represent. -/// -/// As this allows freely converting `u32` to any type that implements -/// `FromPrimitive`, it is only used correctly when the caller is certain of the -/// original error type. -/// -/// [`ProgramError`]: https://docs.rs/solana-program-error/latest/solana_program_error/enum.ProgramError.html -/// [`ProgramError::Custom`]: https://docs.rs/solana-program-error/latest/solana_program_error/enum.ProgramError.html#variant.Custom -/// [`ToPrimitive`]: num_traits::ToPrimitive -#[deprecated(since = "2.3.0", note = "Use `num_traits::FromPrimitive` instead")] -pub trait DecodeError { - fn decode_custom_error_to_enum(custom: u32) -> Option - where - E: FromPrimitive, - { - E::from_u32(custom) - } - fn type_of() -> &'static str; -} - -#[cfg(test)] -#[allow(deprecated)] -mod tests { - use {super::*, num_derive::FromPrimitive}; - - #[test] - fn test_decode_custom_error_to_enum() { - #[derive(Debug, FromPrimitive, PartialEq, Eq)] - enum TestEnum { - A, - B, - C, - } - impl DecodeError for TestEnum { - fn type_of() -> &'static str { - "TestEnum" - } - } - assert_eq!(TestEnum::decode_custom_error_to_enum(0), Some(TestEnum::A)); - assert_eq!(TestEnum::decode_custom_error_to_enum(1), Some(TestEnum::B)); - assert_eq!(TestEnum::decode_custom_error_to_enum(2), Some(TestEnum::C)); - let option: Option = TestEnum::decode_custom_error_to_enum(3); - assert_eq!(option, None); - } -} diff --git a/define-syscall/Cargo.toml b/define-syscall/Cargo.toml index 53466082e..865d1f79e 100644 --- a/define-syscall/Cargo.toml +++ b/define-syscall/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-define-syscall" description = "Solana define_syscall macro and core syscall definitions." documentation = "https://docs.rs/solana-define-syscall" -version = "2.3.0" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/define-syscall/src/definitions.rs b/define-syscall/src/definitions.rs index 0f75edb13..e6586ae5c 100644 --- a/define-syscall/src/definitions.rs +++ b/define-syscall/src/definitions.rs @@ -31,6 +31,7 @@ define_syscall!(fn sol_remaining_compute_units() -> u64); define_syscall!(fn sol_alt_bn128_compression(op: u64, input: *const u8, input_size: u64, result: *mut u8) -> u64); define_syscall!(fn sol_get_sysvar(sysvar_id_addr: *const u8, result: *mut u8, offset: u64, length: u64) -> u64); define_syscall!(fn sol_get_epoch_stake(vote_address: *const u8) -> u64); +define_syscall!(fn sol_panic_(filename: *const u8, filename_len: u64, line: u64, column: u64)); // these are to be deprecated once they are superceded by sol_get_sysvar define_syscall!(fn sol_get_clock_sysvar(addr: *mut u8) -> u64); diff --git a/derivation-path/Cargo.toml b/derivation-path/Cargo.toml index 21092e4fa..0cddd7438 100644 --- a/derivation-path/Cargo.toml +++ b/derivation-path/Cargo.toml @@ -2,7 +2,8 @@ name = "solana-derivation-path" description = "Solana BIP44 derivation paths." documentation = "https://docs.rs/solana-derivation-path" -version = "2.2.1" +version = "3.0.0" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/derivation-path/src/lib.rs b/derivation-path/src/lib.rs index f3deea068..27b2052a6 100644 --- a/derivation-path/src/lib.rs +++ b/derivation-path/src/lib.rs @@ -30,7 +30,7 @@ pub enum DerivationPathError { Infallible, } -impl std::error::Error for DerivationPathError {} +impl core::error::Error for DerivationPathError {} impl fmt::Display for DerivationPathError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -224,7 +224,7 @@ const QUERY_KEY_KEY: &str = "key"; #[derive(Clone, Debug, PartialEq, Eq)] struct QueryKeyError(String); -impl std::error::Error for QueryKeyError {} +impl core::error::Error for QueryKeyError {} impl fmt::Display for QueryKeyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/ed25519-program/Cargo.toml b/ed25519-program/Cargo.toml index 98567f3e8..6053d068a 100644 --- a/ed25519-program/Cargo.toml +++ b/ed25519-program/Cargo.toml @@ -15,20 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytemuck = { workspace = true } bytemuck_derive = { workspace = true } -ed25519-dalek = { workspace = true } -solana-feature-set = { workspace = true } solana-instruction = { workspace = true, features = ["std"] } -solana-precompile-error = { workspace = true } solana-sdk-ids = { workspace = true } -[dev-dependencies] -hex = { workspace = true } -rand0-7 = { workspace = true } -solana-hash = { workspace = true } -solana-keypair = { workspace = true } -solana-logger = { workspace = true } -solana-sdk = { path = "../sdk" } -solana-signer = { workspace = true } - [lints] workspace = true diff --git a/ed25519-program/src/lib.rs b/ed25519-program/src/lib.rs index 1b5dac09e..7d54491fa 100644 --- a/ed25519-program/src/lib.rs +++ b/ed25519-program/src/lib.rs @@ -5,9 +5,7 @@ use { bytemuck::bytes_of, bytemuck_derive::{Pod, Zeroable}, - ed25519_dalek::{ed25519::signature::Signature, Signer, Verifier}, solana_instruction::Instruction, - solana_precompile_error::PrecompileError, }; pub const PUBKEY_SERIALIZED_SIZE: usize = 32; @@ -58,13 +56,6 @@ pub fn offsets_to_ed25519_instruction(offsets: &[Ed25519SignatureOffsets]) -> In } } -#[deprecated(since = "2.2.3", note = "Use new_ed25519_instruction_with_signature")] -pub fn new_ed25519_instruction(keypair: &ed25519_dalek::Keypair, message: &[u8]) -> Instruction { - let signature = keypair.sign(message).to_bytes(); - let pubkey = keypair.public.to_bytes(); - new_ed25519_instruction_with_signature(message, &signature, &pubkey) -} - pub fn new_ed25519_instruction_with_signature( message: &[u8], signature: &[u8; SIGNATURE_SERIALIZED_SIZE], @@ -115,488 +106,3 @@ pub fn new_ed25519_instruction_with_signature( data: instruction_data, } } - -#[deprecated( - since = "2.2.3", - note = "Use agave_precompiles::ed25519::verify instead" -)] -#[allow(deprecated)] -pub fn verify( - data: &[u8], - instruction_datas: &[&[u8]], - feature_set: &solana_feature_set::FeatureSet, -) -> Result<(), PrecompileError> { - if data.len() < SIGNATURE_OFFSETS_START { - return Err(PrecompileError::InvalidInstructionDataSize); - } - let num_signatures = data[0] as usize; - if num_signatures == 0 && data.len() > SIGNATURE_OFFSETS_START { - return Err(PrecompileError::InvalidInstructionDataSize); - } - let expected_data_size = num_signatures - .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) - .saturating_add(SIGNATURE_OFFSETS_START); - // We do not check or use the byte at data[1] - if data.len() < expected_data_size { - return Err(PrecompileError::InvalidInstructionDataSize); - } - for i in 0..num_signatures { - let start = i - .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) - .saturating_add(SIGNATURE_OFFSETS_START); - let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE); - - // bytemuck wants structures aligned - let offsets: &Ed25519SignatureOffsets = bytemuck::try_from_bytes(&data[start..end]) - .map_err(|_| PrecompileError::InvalidDataOffsets)?; - - // Parse out signature - let signature = get_data_slice( - data, - instruction_datas, - offsets.signature_instruction_index, - offsets.signature_offset, - SIGNATURE_SERIALIZED_SIZE, - )?; - - let signature = - Signature::from_bytes(signature).map_err(|_| PrecompileError::InvalidSignature)?; - - // Parse out pubkey - let pubkey = get_data_slice( - data, - instruction_datas, - offsets.public_key_instruction_index, - offsets.public_key_offset, - PUBKEY_SERIALIZED_SIZE, - )?; - - let publickey = ed25519_dalek::PublicKey::from_bytes(pubkey) - .map_err(|_| PrecompileError::InvalidPublicKey)?; - - // Parse out message - let message = get_data_slice( - data, - instruction_datas, - offsets.message_instruction_index, - offsets.message_data_offset, - offsets.message_data_size as usize, - )?; - - if feature_set.is_active(&solana_feature_set::ed25519_precompile_verify_strict::id()) { - publickey - .verify_strict(message, &signature) - .map_err(|_| PrecompileError::InvalidSignature)?; - } else { - publickey - .verify(message, &signature) - .map_err(|_| PrecompileError::InvalidSignature)?; - } - } - Ok(()) -} - -fn get_data_slice<'a>( - data: &'a [u8], - instruction_datas: &'a [&[u8]], - instruction_index: u16, - offset_start: u16, - size: usize, -) -> Result<&'a [u8], PrecompileError> { - let instruction = if instruction_index == u16::MAX { - data - } else { - let signature_index = instruction_index as usize; - if signature_index >= instruction_datas.len() { - return Err(PrecompileError::InvalidDataOffsets); - } - instruction_datas[signature_index] - }; - - let start = offset_start as usize; - let end = start.saturating_add(size); - if end > instruction.len() { - return Err(PrecompileError::InvalidDataOffsets); - } - - Ok(&instruction[start..end]) -} - -#[cfg(test)] -#[allow(deprecated)] -pub mod test { - use { - super::*, - ed25519_dalek::Signer as EdSigner, - hex, - rand0_7::{thread_rng, Rng}, - solana_feature_set::FeatureSet, - solana_hash::Hash, - solana_keypair::Keypair, - solana_sdk::transaction::Transaction, - solana_signer::Signer, - }; - - pub fn new_ed25519_instruction_raw( - pubkey: &[u8], - signature: &[u8], - message: &[u8], - ) -> Instruction { - assert_eq!(pubkey.len(), PUBKEY_SERIALIZED_SIZE); - assert_eq!(signature.len(), SIGNATURE_SERIALIZED_SIZE); - - let mut instruction_data = Vec::with_capacity( - DATA_START - .saturating_add(SIGNATURE_SERIALIZED_SIZE) - .saturating_add(PUBKEY_SERIALIZED_SIZE) - .saturating_add(message.len()), - ); - - let num_signatures: u8 = 1; - let public_key_offset = DATA_START; - let signature_offset = public_key_offset.saturating_add(PUBKEY_SERIALIZED_SIZE); - let message_data_offset = signature_offset.saturating_add(SIGNATURE_SERIALIZED_SIZE); - - // add padding byte so that offset structure is aligned - instruction_data.extend_from_slice(bytes_of(&[num_signatures, 0])); - - let offsets = Ed25519SignatureOffsets { - signature_offset: signature_offset as u16, - signature_instruction_index: u16::MAX, - public_key_offset: public_key_offset as u16, - public_key_instruction_index: u16::MAX, - message_data_offset: message_data_offset as u16, - message_data_size: message.len() as u16, - message_instruction_index: u16::MAX, - }; - - instruction_data.extend_from_slice(bytes_of(&offsets)); - - debug_assert_eq!(instruction_data.len(), public_key_offset); - - instruction_data.extend_from_slice(pubkey); - - debug_assert_eq!(instruction_data.len(), signature_offset); - - instruction_data.extend_from_slice(signature); - - debug_assert_eq!(instruction_data.len(), message_data_offset); - - instruction_data.extend_from_slice(message); - - Instruction { - program_id: solana_sdk_ids::ed25519_program::id(), - accounts: vec![], - data: instruction_data, - } - } - - fn test_case( - num_signatures: u16, - offsets: &Ed25519SignatureOffsets, - ) -> Result<(), PrecompileError> { - assert_eq!( - bytemuck::bytes_of(offsets).len(), - SIGNATURE_OFFSETS_SERIALIZED_SIZE - ); - - let mut instruction_data = vec![0u8; DATA_START]; - instruction_data[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&num_signatures)); - instruction_data[SIGNATURE_OFFSETS_START..DATA_START].copy_from_slice(bytes_of(offsets)); - - verify( - &instruction_data, - &[&[0u8; 100]], - &FeatureSet::all_enabled(), - ) - } - - #[test] - fn test_invalid_offsets() { - solana_logger::setup(); - - let mut instruction_data = vec![0u8; DATA_START]; - let offsets = Ed25519SignatureOffsets::default(); - instruction_data[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&1u16)); - instruction_data[SIGNATURE_OFFSETS_START..DATA_START].copy_from_slice(bytes_of(&offsets)); - instruction_data.truncate(instruction_data.len() - 1); - - assert_eq!( - verify( - &instruction_data, - &[&[0u8; 100]], - &FeatureSet::all_enabled(), - ), - Err(PrecompileError::InvalidInstructionDataSize) - ); - - let offsets = Ed25519SignatureOffsets { - signature_instruction_index: 1, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Ed25519SignatureOffsets { - message_instruction_index: 1, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Ed25519SignatureOffsets { - public_key_instruction_index: 1, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_message_data_offsets() { - let offsets = Ed25519SignatureOffsets { - message_data_offset: 99, - message_data_size: 1, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - - let offsets = Ed25519SignatureOffsets { - message_data_offset: 100, - message_data_size: 1, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Ed25519SignatureOffsets { - message_data_offset: 100, - message_data_size: 1000, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Ed25519SignatureOffsets { - message_data_offset: u16::MAX, - message_data_size: u16::MAX, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_pubkey_offset() { - let offsets = Ed25519SignatureOffsets { - public_key_offset: u16::MAX, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Ed25519SignatureOffsets { - public_key_offset: 100 - PUBKEY_SERIALIZED_SIZE as u16 + 1, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_signature_offset() { - let offsets = Ed25519SignatureOffsets { - signature_offset: u16::MAX, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Ed25519SignatureOffsets { - signature_offset: 100 - SIGNATURE_SERIALIZED_SIZE as u16 + 1, - ..Ed25519SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_ed25519() { - solana_logger::setup(); - - let privkey = ed25519_dalek::Keypair::generate(&mut thread_rng()); - let message_arr = b"hello"; - let signature = privkey.sign(message_arr).to_bytes(); - let pubkey = privkey.public.to_bytes(); - let mut instruction = - new_ed25519_instruction_with_signature(message_arr, &signature, &pubkey); - let mint_keypair = Keypair::new(); - let feature_set = FeatureSet::all_enabled(); - - let tx = Transaction::new_signed_with_payer( - &[instruction.clone()], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - - assert!(tx.verify_precompiles(&feature_set).is_ok()); - - let index = loop { - let index = thread_rng().gen_range(0, instruction.data.len()); - // byte 1 is not used, so this would not cause the verify to fail - if index != 1 { - break index; - } - }; - - instruction.data[index] = instruction.data[index].wrapping_add(12); - let tx = Transaction::new_signed_with_payer( - &[instruction], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - assert!(tx.verify_precompiles(&feature_set).is_err()); - } - - #[test] - fn test_offsets_to_ed25519_instruction() { - solana_logger::setup(); - - let privkey = ed25519_dalek::Keypair::generate(&mut thread_rng()); - let messages: [&[u8]; 3] = [b"hello", b"IBRL", b"goodbye"]; - let data_start = - messages.len() * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START; - let mut data_offset = data_start + PUBKEY_SERIALIZED_SIZE; - let (offsets, messages): (Vec<_>, Vec<_>) = messages - .into_iter() - .map(|message| { - let signature_offset = data_offset; - let message_data_offset = signature_offset + SIGNATURE_SERIALIZED_SIZE; - data_offset += SIGNATURE_SERIALIZED_SIZE + message.len(); - - let offsets = Ed25519SignatureOffsets { - signature_offset: signature_offset as u16, - signature_instruction_index: u16::MAX, - public_key_offset: data_start as u16, - public_key_instruction_index: u16::MAX, - message_data_offset: message_data_offset as u16, - message_data_size: message.len() as u16, - message_instruction_index: u16::MAX, - }; - - (offsets, message) - }) - .unzip(); - - let mut instruction = offsets_to_ed25519_instruction(&offsets); - - let pubkey = privkey.public.as_ref(); - instruction.data.extend_from_slice(pubkey); - - for message in messages { - let signature = privkey.sign(message).to_bytes(); - instruction.data.extend_from_slice(&signature); - instruction.data.extend_from_slice(message); - } - - let mint_keypair = Keypair::new(); - let feature_set = FeatureSet::all_enabled(); - - let tx = Transaction::new_signed_with_payer( - &[instruction.clone()], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - - assert!(tx.verify_precompiles(&feature_set).is_ok()); - - let index = loop { - let index = thread_rng().gen_range(0, instruction.data.len()); - // byte 1 is not used, so this would not cause the verify to fail - if index != 1 { - break index; - } - }; - - instruction.data[index] = instruction.data[index].wrapping_add(12); - let tx = Transaction::new_signed_with_payer( - &[instruction], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - assert!(tx.verify_precompiles(&feature_set).is_err()); - } - - #[test] - fn test_ed25519_malleability() { - solana_logger::setup(); - let mint_keypair = Keypair::new(); - - // sig created via ed25519_dalek: both pass - let privkey = ed25519_dalek::Keypair::generate(&mut thread_rng()); - let message_arr = b"hello"; - let instruction = new_ed25519_instruction(&privkey, message_arr); - let tx = Transaction::new_signed_with_payer( - &[instruction.clone()], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - - let feature_set = FeatureSet::default(); - assert!(tx.verify_precompiles(&feature_set).is_ok()); - - let feature_set = FeatureSet::all_enabled(); - assert!(tx.verify_precompiles(&feature_set).is_ok()); - - // malleable sig: verify_strict does NOT pass - // for example, test number 5: - // https://github.com/C2SP/CCTV/tree/main/ed25519 - // R has low order (in fact R == 0) - let pubkey = - &hex::decode("10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f") - .unwrap(); - let signature = &hex::decode("00000000000000000000000000000000000000000000000000000000000000009472a69cd9a701a50d130ed52189e2455b23767db52cacb8716fb896ffeeac09").unwrap(); - let message = b"ed25519vectors 3"; - let instruction = new_ed25519_instruction_raw(pubkey, signature, message); - let tx = Transaction::new_signed_with_payer( - &[instruction.clone()], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - - let feature_set = FeatureSet::default(); - assert!(tx.verify_precompiles(&feature_set).is_ok()); - - let feature_set = FeatureSet::all_enabled(); - assert!(tx.verify_precompiles(&feature_set).is_err()); // verify_strict does NOT pass - } -} diff --git a/epoch-info/Cargo.toml b/epoch-info/Cargo.toml index 48430f4b6..0dd7fc9be 100644 --- a/epoch-info/Cargo.toml +++ b/epoch-info/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-epoch-info" description = "Information about a Solana epoch." documentation = "https://docs.rs/solana-epoch-info" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/epoch-rewards-hasher/src/lib.rs b/epoch-rewards-hasher/src/lib.rs index a9e910058..aa4aed7e6 100644 --- a/epoch-rewards-hasher/src/lib.rs +++ b/epoch-rewards-hasher/src/lib.rs @@ -123,11 +123,7 @@ mod tests { // size is same or 1 less assert!( len == expected_len_of_partition || len + 1 == expected_len_of_partition, - "{}, {}, {}, {}", - expected_len_of_partition, - len, - partition, - partitions + "{expected_len_of_partition}, {len}, {partition}, {partitions}", ); } } diff --git a/rent-debits/Cargo.toml b/epoch-stake/Cargo.toml similarity index 63% rename from rent-debits/Cargo.toml rename to epoch-stake/Cargo.toml index d2b2b5e9c..1648c2c82 100644 --- a/rent-debits/Cargo.toml +++ b/epoch-stake/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "solana-rent-debits" -description = "Solana rent debit types." -documentation = "https://docs.rs/solana-rent-debits" +name = "solana-epoch-stake" +description = "Solana epoch stake syscall API" +documentation = "https://docs.rs/solana-epoch-stake" version = "2.2.1" authors = { workspace = true } repository = { workspace = true } @@ -14,12 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] all-features = true rustdoc-args = ["--cfg=docsrs"] -[features] -dev-context-only-utils = [] - [dependencies] solana-pubkey = { workspace = true } -solana-reward-info = { workspace = true } + +[target.'cfg(target_os = "solana")'.dependencies] +solana-define-syscall = { workspace = true } [lints] workspace = true diff --git a/program/src/epoch_stake.rs b/epoch-stake/src/lib.rs similarity index 81% rename from program/src/epoch_stake.rs rename to epoch-stake/src/lib.rs index cf8efd2eb..864f202af 100644 --- a/program/src/epoch_stake.rs +++ b/epoch-stake/src/lib.rs @@ -4,16 +4,19 @@ //! current epoch or the stake for a specific vote account using the //! `sol_get_epoch_stake` syscall. -use crate::pubkey::Pubkey; +use solana_pubkey::Pubkey; fn get_epoch_stake(var_addr: *const u8) -> u64 { #[cfg(target_os = "solana")] - let result = unsafe { crate::syscalls::sol_get_epoch_stake(var_addr) }; + { + unsafe { solana_define_syscall::definitions::sol_get_epoch_stake(var_addr) } + } #[cfg(not(target_os = "solana"))] - let result = crate::program_stubs::sol_get_epoch_stake(var_addr); - - result + { + core::hint::black_box(var_addr); + 0 + } } /// Get the current epoch's total stake. diff --git a/example-mocks/Cargo.toml b/example-mocks/Cargo.toml index 17ae55910..b3f99ba65 100644 --- a/example-mocks/Cargo.toml +++ b/example-mocks/Cargo.toml @@ -11,6 +11,11 @@ edition = { workspace = true } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] +all-features = true +rustdoc-args = ["--cfg=docsrs"] + +[features] +bincode = ["solana-system-interface/bincode"] [dependencies] serde = { workspace = true } diff --git a/example-mocks/src/lib.rs b/example-mocks/src/lib.rs index 5cf880caf..95e35ef7f 100644 --- a/example-mocks/src/lib.rs +++ b/example-mocks/src/lib.rs @@ -12,6 +12,7 @@ #![doc(hidden)] #![allow(clippy::new_without_default)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod solana_rpc_client { pub mod rpc_client { @@ -110,14 +111,13 @@ pub mod solana_rpc_client_nonce_utils { } pub mod solana_account { - use {solana_clock::Epoch, solana_pubkey::Pubkey}; + use solana_pubkey::Pubkey; #[derive(Clone)] pub struct Account { pub lamports: u64, pub data: Vec, pub owner: Pubkey, pub executable: bool, - pub rent_epoch: Epoch, } pub trait ReadableAccount: Sized { diff --git a/feature-gate-interface/src/lib.rs b/feature-gate-interface/src/lib.rs index e431a90a2..b38fe4863 100644 --- a/feature-gate-interface/src/lib.rs +++ b/feature-gate-interface/src/lib.rs @@ -145,7 +145,6 @@ mod test { &mut good_data, &id(), false, - u64::MAX, )), Ok(Feature { activated_at: None }) ); @@ -158,7 +157,6 @@ mod test { &mut small_data, // Too small &id(), false, - u64::MAX, )), Err(ProgramError::InvalidAccountData), ); @@ -171,7 +169,6 @@ mod test { &mut good_data, &Pubkey::new_unique(), // Wrong owner false, - u64::MAX, )), Err(ProgramError::InvalidAccountOwner), ); diff --git a/feature-set-interface/Cargo.toml b/feature-set-interface/Cargo.toml deleted file mode 100644 index c57d888ff..000000000 --- a/feature-set-interface/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "solana-feature-set-interface" -description = "Interface for Solana runtime features." -documentation = "https://docs.rs/solana-feature-set-interface" -version = "4.0.1" -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -license = { workspace = true } -edition = { workspace = true } - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[features] -frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"] - -[dependencies] -ahash = { workspace = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-frozen-abi-macro = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-pubkey = { workspace = true } - -[lints] -workspace = true diff --git a/feature-set-interface/src/lib.rs b/feature-set-interface/src/lib.rs deleted file mode 100644 index 8ef08e873..000000000 --- a/feature-set-interface/src/lib.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] -#![deprecated( - since = "4.0.1", - note = "DO NOT USE. Crates that need to break consensus should expose their own minimal configuration type" -)] - -use { - ahash::{AHashMap, AHashSet}, - solana_pubkey::Pubkey, -}; - -/// `FeatureSet` holds the set of currently active/inactive runtime features -#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct FeatureSet { - pub active: AHashMap, - pub inactive: AHashSet, -} - -impl FeatureSet { - pub fn is_active(&self, feature_id: &Pubkey) -> bool { - self.active.contains_key(feature_id) - } - - pub fn activated_slot(&self, feature_id: &Pubkey) -> Option { - self.active.get(feature_id).copied() - } - - /// Activate a feature - pub fn activate(&mut self, feature_id: &Pubkey, slot: u64) { - self.inactive.remove(feature_id); - self.active.insert(*feature_id, slot); - } - - /// Deactivate a feature - pub fn deactivate(&mut self, feature_id: &Pubkey) { - self.active.remove(feature_id); - self.inactive.insert(*feature_id); - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_feature_set_activate_deactivate() { - let mut feature_set = FeatureSet { - active: AHashMap::new(), - inactive: AHashSet::new(), - }; - - let feature = Pubkey::new_unique(); - assert!(!feature_set.is_active(&feature)); - feature_set.activate(&feature, 0); - assert!(feature_set.is_active(&feature)); - feature_set.deactivate(&feature); - assert!(!feature_set.is_active(&feature)); - } -} diff --git a/feature-set/Cargo.toml b/feature-set/Cargo.toml deleted file mode 100644 index a3c33405f..000000000 --- a/feature-set/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "solana-feature-set" -description = "Solana runtime features." -documentation = "https://docs.rs/solana-feature-set" -version = "2.2.5" -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -license = { workspace = true } -edition = { workspace = true } - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[features] -frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"] - -[dependencies] -ahash = { workspace = true } -lazy_static = { workspace = true } -solana-epoch-schedule = { workspace = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-frozen-abi-macro = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-hash = { workspace = true } -solana-pubkey = { workspace = true } -solana-sha256-hasher = { workspace = true } - -[lints] -workspace = true diff --git a/feature-set/src/lib.rs b/feature-set/src/lib.rs deleted file mode 100644 index 8e1028bb6..000000000 --- a/feature-set/src/lib.rs +++ /dev/null @@ -1,1366 +0,0 @@ -//! Collection of all runtime features. -//! -//! Steps to add a new feature are outlined below. Note that these steps only cover -//! the process of getting a feature into the core Solana code. -//! - For features that are unambiguously good (ie bug fixes), these steps are sufficient. -//! - For features that should go up for community vote (ie fee structure changes), more -//! information on the additional steps to follow can be found at: -//! -//! -//! 1. Generate a new keypair with `solana-keygen new --outfile feature.json --no-passphrase` -//! - Keypairs should be held by core contributors only. If you're a non-core contributor going -//! through these steps, the PR process will facilitate a keypair holder being picked. That -//! person will generate the keypair, provide pubkey for PR, and ultimately enable the feature. -//! 2. Add a public module for the feature, specifying keypair pubkey as the id with -//! `solana_pubkey::declare_id!()` within the module. -//! Additionally, add an entry to `FEATURE_NAMES` map. -//! 3. Add desired logic to check for and switch on feature availability. -//! -//! For more information on how features are picked up, see comments for `Feature`. -#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] -#![deprecated(since = "2.2.5", note = "Use agave-feature-set instead")] - -use { - ahash::{AHashMap, AHashSet}, - lazy_static::lazy_static, - solana_epoch_schedule::EpochSchedule, - solana_hash::Hash, - solana_pubkey::Pubkey, - solana_sha256_hasher::Hasher, -}; - -pub mod deprecate_rewards_sysvar { - solana_pubkey::declare_id!("GaBtBJvmS4Arjj5W1NmFcyvPjsHN38UGYDq2MDwbs9Qu"); -} - -pub mod pico_inflation { - solana_pubkey::declare_id!("4RWNif6C2WCNiKVW7otP4G7dkmkHGyKQWRpuZ1pxKU5m"); -} - -pub mod full_inflation { - pub mod devnet_and_testnet { - solana_pubkey::declare_id!("DT4n6ABDqs6w4bnfwrXT9rsprcPf6cdDga1egctaPkLC"); - } - - pub mod mainnet { - pub mod certusone { - pub mod vote { - solana_pubkey::declare_id!("BzBBveUDymEYoYzcMWNQCx3cd4jQs7puaVFHLtsbB6fm"); - } - pub mod enable { - solana_pubkey::declare_id!("7XRJcS5Ud5vxGB54JbK9N2vBZVwnwdBNeJW1ibRgD9gx"); - } - } - } -} - -pub mod secp256k1_program_enabled { - solana_pubkey::declare_id!("E3PHP7w8kB7np3CTQ1qQ2tW3KCtjRSXBQgW9vM2mWv2Y"); -} - -pub mod spl_token_v2_multisig_fix { - solana_pubkey::declare_id!("E5JiFDQCwyC6QfT9REFyMpfK2mHcmv1GUDySU1Ue7TYv"); -} - -pub mod no_overflow_rent_distribution { - solana_pubkey::declare_id!("4kpdyrcj5jS47CZb2oJGfVxjYbsMm2Kx97gFyZrxxwXz"); -} - -pub mod filter_stake_delegation_accounts { - solana_pubkey::declare_id!("GE7fRxmW46K6EmCD9AMZSbnaJ2e3LfqCZzdHi9hmYAgi"); -} - -pub mod require_custodian_for_locked_stake_authorize { - solana_pubkey::declare_id!("D4jsDcXaqdW8tDAWn8H4R25Cdns2YwLneujSL1zvjW6R"); -} - -pub mod spl_token_v2_self_transfer_fix { - solana_pubkey::declare_id!("BL99GYhdjjcv6ys22C9wPgn2aTVERDbPHHo4NbS3hgp7"); -} - -pub mod warp_timestamp_again { - solana_pubkey::declare_id!("GvDsGDkH5gyzwpDhxNixx8vtx1kwYHH13RiNAPw27zXb"); -} - -pub mod check_init_vote_data { - solana_pubkey::declare_id!("3ccR6QpxGYsAbWyfevEtBNGfWV4xBffxRj2tD6A9i39F"); -} - -pub mod secp256k1_recover_syscall_enabled { - solana_pubkey::declare_id!("6RvdSWHh8oh72Dp7wMTS2DBkf3fRPtChfNrAo3cZZoXJ"); -} - -pub mod system_transfer_zero_check { - solana_pubkey::declare_id!("BrTR9hzw4WBGFP65AJMbpAo64DcA3U6jdPSga9fMV5cS"); -} - -pub mod blake3_syscall_enabled { - solana_pubkey::declare_id!("HTW2pSyErTj4BV6KBM9NZ9VBUJVxt7sacNWcf76wtzb3"); -} - -pub mod dedupe_config_program_signers { - solana_pubkey::declare_id!("8kEuAshXLsgkUEdcFVLqrjCGGHVWFW99ZZpxvAzzMtBp"); -} - -pub mod verify_tx_signatures_len { - solana_pubkey::declare_id!("EVW9B5xD9FFK7vw1SBARwMA4s5eRo5eKJdKpsBikzKBz"); -} - -pub mod vote_stake_checked_instructions { - solana_pubkey::declare_id!("BcWknVcgvonN8sL4HE4XFuEVgfcee5MwxWPAgP6ZV89X"); -} - -pub mod rent_for_sysvars { - solana_pubkey::declare_id!("BKCPBQQBZqggVnFso5nQ8rQ4RwwogYwjuUt9biBjxwNF"); -} - -pub mod libsecp256k1_0_5_upgrade_enabled { - solana_pubkey::declare_id!("DhsYfRjxfnh2g7HKJYSzT79r74Afa1wbHkAgHndrA1oy"); -} - -pub mod tx_wide_compute_cap { - solana_pubkey::declare_id!("5ekBxc8itEnPv4NzGJtr8BVVQLNMQuLMNQQj7pHoLNZ9"); -} - -pub mod spl_token_v2_set_authority_fix { - solana_pubkey::declare_id!("FToKNBYyiF4ky9s8WsmLBXHCht17Ek7RXaLZGHzzQhJ1"); -} - -pub mod merge_nonce_error_into_system_error { - solana_pubkey::declare_id!("21AWDosvp3pBamFW91KB35pNoaoZVTM7ess8nr2nt53B"); -} - -pub mod disable_fees_sysvar { - solana_pubkey::declare_id!("JAN1trEUEtZjgXYzNBYHU9DYd7GnThhXfFP7SzPXkPsG"); -} - -pub mod stake_merge_with_unmatched_credits_observed { - solana_pubkey::declare_id!("meRgp4ArRPhD3KtCY9c5yAf2med7mBLsjKTPeVUHqBL"); -} - -pub mod zk_token_sdk_enabled { - solana_pubkey::declare_id!("zk1snxsc6Fh3wsGNbbHAJNHiJoYgF29mMnTSusGx5EJ"); -} - -pub mod curve25519_syscall_enabled { - solana_pubkey::declare_id!("7rcw5UtqgDTBBv2EcynNfYckgdAaH1MAsCjKgXMkN7Ri"); -} - -pub mod curve25519_restrict_msm_length { - solana_pubkey::declare_id!("eca6zf6JJRjQsYYPkBHF3N32MTzur4n2WL4QiiacPCL"); -} - -pub mod versioned_tx_message_enabled { - solana_pubkey::declare_id!("3KZZ6Ks1885aGBQ45fwRcPXVBCtzUvxhUTkwKMR41Tca"); -} - -pub mod libsecp256k1_fail_on_bad_count { - solana_pubkey::declare_id!("8aXvSuopd1PUj7UhehfXJRg6619RHp8ZvwTyyJHdUYsj"); -} - -pub mod libsecp256k1_fail_on_bad_count2 { - solana_pubkey::declare_id!("54KAoNiUERNoWWUhTWWwXgym94gzoXFVnHyQwPA18V9A"); -} - -pub mod instructions_sysvar_owned_by_sysvar { - solana_pubkey::declare_id!("H3kBSaKdeiUsyHmeHqjJYNc27jesXZ6zWj3zWkowQbkV"); -} - -pub mod stake_program_advance_activating_credits_observed { - solana_pubkey::declare_id!("SAdVFw3RZvzbo6DvySbSdBnHN4gkzSTH9dSxesyKKPj"); -} - -pub mod credits_auto_rewind { - solana_pubkey::declare_id!("BUS12ciZ5gCoFafUHWW8qaFMMtwFQGVxjsDheWLdqBE2"); -} - -pub mod demote_program_write_locks { - solana_pubkey::declare_id!("3E3jV7v9VcdJL8iYZUMax9DiDno8j7EWUVbhm9RtShj2"); -} - -pub mod ed25519_program_enabled { - solana_pubkey::declare_id!("6ppMXNYLhVd7GcsZ5uV11wQEW7spppiMVfqQv5SXhDpX"); -} - -pub mod return_data_syscall_enabled { - solana_pubkey::declare_id!("DwScAzPUjuv65TMbDnFY7AgwmotzWy3xpEJMXM3hZFaB"); -} - -pub mod reduce_required_deploy_balance { - solana_pubkey::declare_id!("EBeznQDjcPG8491sFsKZYBi5S5jTVXMpAKNDJMQPS2kq"); -} - -pub mod sol_log_data_syscall_enabled { - solana_pubkey::declare_id!("6uaHcKPGUy4J7emLBgUTeufhJdiwhngW6a1R9B7c2ob9"); -} - -pub mod stakes_remove_delegation_if_inactive { - solana_pubkey::declare_id!("HFpdDDNQjvcXnXKec697HDDsyk6tFoWS2o8fkxuhQZpL"); -} - -pub mod do_support_realloc { - solana_pubkey::declare_id!("75m6ysz33AfLA5DDEzWM1obBrnPQRSsdVQ2nRmc8Vuu1"); -} - -pub mod prevent_calling_precompiles_as_programs { - solana_pubkey::declare_id!("4ApgRX3ud6p7LNMJmsuaAcZY5HWctGPr5obAsjB3A54d"); -} - -pub mod optimize_epoch_boundary_updates { - solana_pubkey::declare_id!("265hPS8k8xJ37ot82KEgjRunsUp5w4n4Q4VwwiN9i9ps"); -} - -pub mod remove_native_loader { - solana_pubkey::declare_id!("HTTgmruMYRZEntyL3EdCDdnS6e4D5wRq1FA7kQsb66qq"); -} - -pub mod send_to_tpu_vote_port { - solana_pubkey::declare_id!("C5fh68nJ7uyKAuYZg2x9sEQ5YrVf3dkW6oojNBSc3Jvo"); -} - -pub mod requestable_heap_size { - solana_pubkey::declare_id!("CCu4boMmfLuqcmfTLPHQiUo22ZdUsXjgzPAURYaWt1Bw"); -} - -pub mod disable_fee_calculator { - solana_pubkey::declare_id!("2jXx2yDmGysmBKfKYNgLj2DQyAQv6mMk2BPh4eSbyB4H"); -} - -pub mod add_compute_budget_program { - solana_pubkey::declare_id!("4d5AKtxoh93Dwm1vHXUU3iRATuMndx1c431KgT2td52r"); -} - -pub mod nonce_must_be_writable { - solana_pubkey::declare_id!("BiCU7M5w8ZCMykVSyhZ7Q3m2SWoR2qrEQ86ERcDX77ME"); -} - -pub mod spl_token_v3_3_0_release { - solana_pubkey::declare_id!("Ftok2jhqAqxUWEiCVRrfRs9DPppWP8cgTB7NQNKL88mS"); -} - -pub mod leave_nonce_on_success { - solana_pubkey::declare_id!("E8MkiWZNNPGU6n55jkGzyj8ghUmjCHRmDFdYYFYHxWhQ"); -} - -pub mod reject_empty_instruction_without_program { - solana_pubkey::declare_id!("9kdtFSrXHQg3hKkbXkQ6trJ3Ja1xpJ22CTFSNAciEwmL"); -} - -pub mod fixed_memcpy_nonoverlapping_check { - solana_pubkey::declare_id!("36PRUK2Dz6HWYdG9SpjeAsF5F3KxnFCakA2BZMbtMhSb"); -} - -pub mod reject_non_rent_exempt_vote_withdraws { - solana_pubkey::declare_id!("7txXZZD6Um59YoLMF7XUNimbMjsqsWhc7g2EniiTrmp1"); -} - -pub mod evict_invalid_stakes_cache_entries { - solana_pubkey::declare_id!("EMX9Q7TVFAmQ9V1CggAkhMzhXSg8ECp7fHrWQX2G1chf"); -} - -pub mod allow_votes_to_directly_update_vote_state { - solana_pubkey::declare_id!("Ff8b1fBeB86q8cjq47ZhsQLgv5EkHu3G1C99zjUfAzrq"); -} - -pub mod max_tx_account_locks { - solana_pubkey::declare_id!("CBkDroRDqm8HwHe6ak9cguPjUomrASEkfmxEaZ5CNNxz"); -} - -pub mod require_rent_exempt_accounts { - solana_pubkey::declare_id!("BkFDxiJQWZXGTZaJQxH7wVEHkAmwCgSEVkrvswFfRJPD"); -} - -pub mod filter_votes_outside_slot_hashes { - solana_pubkey::declare_id!("3gtZPqvPpsbXZVCx6hceMfWxtsmrjMzmg8C7PLKSxS2d"); -} - -pub mod update_syscall_base_costs { - solana_pubkey::declare_id!("2h63t332mGCCsWK2nqqqHhN4U9ayyqhLVFvczznHDoTZ"); -} - -pub mod stake_deactivate_delinquent_instruction { - solana_pubkey::declare_id!("437r62HoAdUb63amq3D7ENnBLDhHT2xY8eFkLJYVKK4x"); -} - -pub mod vote_withdraw_authority_may_change_authorized_voter { - solana_pubkey::declare_id!("AVZS3ZsN4gi6Rkx2QUibYuSJG3S6QHib7xCYhG6vGJxU"); -} - -pub mod spl_associated_token_account_v1_0_4 { - solana_pubkey::declare_id!("FaTa4SpiaSNH44PGC4z8bnGVTkSRYaWvrBs3KTu8XQQq"); -} - -pub mod reject_vote_account_close_unless_zero_credit_epoch { - solana_pubkey::declare_id!("ALBk3EWdeAg2WAGf6GPDUf1nynyNqCdEVmgouG7rpuCj"); -} - -pub mod add_get_processed_sibling_instruction_syscall { - solana_pubkey::declare_id!("CFK1hRCNy8JJuAAY8Pb2GjLFNdCThS2qwZNe3izzBMgn"); -} - -pub mod bank_transaction_count_fix { - solana_pubkey::declare_id!("Vo5siZ442SaZBKPXNocthiXysNviW4UYPwRFggmbgAp"); -} - -pub mod disable_bpf_deprecated_load_instructions { - solana_pubkey::declare_id!("3XgNukcZWf9o3HdA3fpJbm94XFc4qpvTXc8h1wxYwiPi"); -} - -pub mod disable_bpf_unresolved_symbols_at_runtime { - solana_pubkey::declare_id!("4yuaYAj2jGMGTh1sSmi4G2eFscsDq8qjugJXZoBN6YEa"); -} - -pub mod record_instruction_in_transaction_context_push { - solana_pubkey::declare_id!("3aJdcZqxoLpSBxgeYGjPwaYS1zzcByxUDqJkbzWAH1Zb"); -} - -pub mod syscall_saturated_math { - solana_pubkey::declare_id!("HyrbKftCdJ5CrUfEti6x26Cj7rZLNe32weugk7tLcWb8"); -} - -pub mod check_physical_overlapping { - solana_pubkey::declare_id!("nWBqjr3gpETbiaVj3CBJ3HFC5TMdnJDGt21hnvSTvVZ"); -} - -pub mod limit_secp256k1_recovery_id { - solana_pubkey::declare_id!("7g9EUwj4j7CS21Yx1wvgWLjSZeh5aPq8x9kpoPwXM8n8"); -} - -pub mod disable_deprecated_loader { - solana_pubkey::declare_id!("GTUMCZ8LTNxVfxdrw7ZsDFTxXb7TutYkzJnFwinpE6dg"); -} - -pub mod check_slice_translation_size { - solana_pubkey::declare_id!("GmC19j9qLn2RFk5NduX6QXaDhVpGncVVBzyM8e9WMz2F"); -} - -pub mod stake_split_uses_rent_sysvar { - solana_pubkey::declare_id!("FQnc7U4koHqWgRvFaBJjZnV8VPg6L6wWK33yJeDp4yvV"); -} - -pub mod add_get_minimum_delegation_instruction_to_stake_program { - solana_pubkey::declare_id!("St8k9dVXP97xT6faW24YmRSYConLbhsMJA4TJTBLmMT"); -} - -pub mod error_on_syscall_bpf_function_hash_collisions { - solana_pubkey::declare_id!("8199Q2gMD2kwgfopK5qqVWuDbegLgpuFUFHCcUJQDN8b"); -} - -pub mod reject_callx_r10 { - solana_pubkey::declare_id!("3NKRSwpySNwD3TvP5pHnRmkAQRsdkXWRr1WaQh8p4PWX"); -} - -pub mod drop_redundant_turbine_path { - solana_pubkey::declare_id!("4Di3y24QFLt5QEUPZtbnjyfQKfm6ZMTfa6Dw1psfoMKU"); -} - -pub mod executables_incur_cpi_data_cost { - solana_pubkey::declare_id!("7GUcYgq4tVtaqNCKT3dho9r4665Qp5TxCZ27Qgjx3829"); -} - -pub mod fix_recent_blockhashes { - solana_pubkey::declare_id!("6iyggb5MTcsvdcugX7bEKbHV8c6jdLbpHwkncrgLMhfo"); -} - -pub mod update_rewards_from_cached_accounts { - solana_pubkey::declare_id!("28s7i3htzhahXQKqmS2ExzbEoUypg9krwvtK2M9UWXh9"); -} -pub mod enable_partitioned_epoch_reward { - solana_pubkey::declare_id!("9bn2vTJUsUcnpiZWbu2woSKtTGW3ErZC9ERv88SDqQjK"); -} - -pub mod partitioned_epoch_rewards_superfeature { - solana_pubkey::declare_id!("PERzQrt5gBD1XEe2c9XdFWqwgHY3mr7cYWbm5V772V8"); -} - -pub mod spl_token_v3_4_0 { - solana_pubkey::declare_id!("Ftok4njE8b7tDffYkC5bAbCaQv5sL6jispYrprzatUwN"); -} - -pub mod spl_associated_token_account_v1_1_0 { - solana_pubkey::declare_id!("FaTa17gVKoqbh38HcfiQonPsAaQViyDCCSg71AubYZw8"); -} - -pub mod default_units_per_instruction { - solana_pubkey::declare_id!("J2QdYx8crLbTVK8nur1jeLsmc3krDbfjoxoea2V1Uy5Q"); -} - -pub mod stake_allow_zero_undelegated_amount { - solana_pubkey::declare_id!("sTKz343FM8mqtyGvYWvbLpTThw3ixRM4Xk8QvZ985mw"); -} - -pub mod require_static_program_ids_in_transaction { - solana_pubkey::declare_id!("8FdwgyHFEjhAdjWfV2vfqk7wA1g9X3fQpKH7SBpEv3kC"); -} - -pub mod stake_raise_minimum_delegation_to_1_sol { - // This is a feature-proposal *feature id*. The feature keypair address is `GQXzC7YiSNkje6FFUk6sc2p53XRvKoaZ9VMktYzUMnpL`. - solana_pubkey::declare_id!("9onWzzvCzNC2jfhxxeqRgs5q7nFAAKpCUvkj6T6GJK9i"); -} - -pub mod stake_minimum_delegation_for_rewards { - solana_pubkey::declare_id!("G6ANXD6ptCSyNd9znZm7j4dEczAJCfx7Cy43oBx3rKHJ"); -} - -pub mod add_set_compute_unit_price_ix { - solana_pubkey::declare_id!("98std1NSHqXi9WYvFShfVepRdCoq1qvsp8fsR2XZtG8g"); -} - -pub mod disable_deploy_of_alloc_free_syscall { - solana_pubkey::declare_id!("79HWsX9rpnnJBPcdNURVqygpMAfxdrAirzAGAVmf92im"); -} - -pub mod include_account_index_in_rent_error { - solana_pubkey::declare_id!("2R72wpcQ7qV7aTJWUumdn8u5wmmTyXbK7qzEy7YSAgyY"); -} - -pub mod add_shred_type_to_shred_seed { - solana_pubkey::declare_id!("Ds87KVeqhbv7Jw8W6avsS1mqz3Mw5J3pRTpPoDQ2QdiJ"); -} - -pub mod warp_timestamp_with_a_vengeance { - solana_pubkey::declare_id!("3BX6SBeEBibHaVQXywdkcgyUk6evfYZkHdztXiDtEpFS"); -} - -pub mod separate_nonce_from_blockhash { - solana_pubkey::declare_id!("Gea3ZkK2N4pHuVZVxWcnAtS6UEDdyumdYt4pFcKjA3ar"); -} - -pub mod enable_durable_nonce { - solana_pubkey::declare_id!("4EJQtF2pkRyawwcTVfQutzq4Sa5hRhibF6QAK1QXhtEX"); -} - -pub mod vote_state_update_credit_per_dequeue { - solana_pubkey::declare_id!("CveezY6FDLVBToHDcvJRmtMouqzsmj4UXYh5ths5G5Uv"); -} - -pub mod quick_bail_on_panic { - solana_pubkey::declare_id!("DpJREPyuMZ5nDfU6H3WTqSqUFSXAfw8u7xqmWtEwJDcP"); -} - -pub mod nonce_must_be_authorized { - solana_pubkey::declare_id!("HxrEu1gXuH7iD3Puua1ohd5n4iUKJyFNtNxk9DVJkvgr"); -} - -pub mod nonce_must_be_advanceable { - solana_pubkey::declare_id!("3u3Er5Vc2jVcwz4xr2GJeSAXT3fAj6ADHZ4BJMZiScFd"); -} - -pub mod vote_authorize_with_seed { - solana_pubkey::declare_id!("6tRxEYKuy2L5nnv5bgn7iT28MxUbYxp5h7F3Ncf1exrT"); -} - -pub mod preserve_rent_epoch_for_rent_exempt_accounts { - solana_pubkey::declare_id!("HH3MUYReL2BvqqA3oEcAa7txju5GY6G4nxJ51zvsEjEZ"); -} - -pub mod enable_bpf_loader_extend_program_ix { - solana_pubkey::declare_id!("8Zs9W7D9MpSEtUWSQdGniZk2cNmV22y6FLJwCx53asme"); -} - -pub mod enable_early_verification_of_account_modifications { - solana_pubkey::declare_id!("7Vced912WrRnfjaiKRiNBcbuFw7RrnLv3E3z95Y4GTNc"); -} - -pub mod skip_rent_rewrites { - solana_pubkey::declare_id!("CGB2jM8pwZkeeiXQ66kBMyBR6Np61mggL7XUsmLjVcrw"); -} - -pub mod prevent_crediting_accounts_that_end_rent_paying { - solana_pubkey::declare_id!("812kqX67odAp5NFwM8D2N24cku7WTm9CHUTFUXaDkWPn"); -} - -pub mod cap_bpf_program_instruction_accounts { - solana_pubkey::declare_id!("9k5ijzTbYPtjzu8wj2ErH9v45xecHzQ1x4PMYMMxFgdM"); -} - -pub mod loosen_cpi_size_restriction { - solana_pubkey::declare_id!("GDH5TVdbTPUpRnXaRyQqiKUa7uZAbZ28Q2N9bhbKoMLm"); -} - -pub mod use_default_units_in_fee_calculation { - solana_pubkey::declare_id!("8sKQrMQoUHtQSUP83SPG4ta2JDjSAiWs7t5aJ9uEd6To"); -} - -pub mod compact_vote_state_updates { - solana_pubkey::declare_id!("86HpNqzutEZwLcPxS6EHDcMNYWk6ikhteg9un7Y2PBKE"); -} - -pub mod incremental_snapshot_only_incremental_hash_calculation { - solana_pubkey::declare_id!("25vqsfjk7Nv1prsQJmA4Xu1bN61s8LXCBGUPp8Rfy1UF"); -} - -pub mod disable_cpi_setting_executable_and_rent_epoch { - solana_pubkey::declare_id!("B9cdB55u4jQsDNsdTK525yE9dmSc5Ga7YBaBrDFvEhM9"); -} - -pub mod on_load_preserve_rent_epoch_for_rent_exempt_accounts { - solana_pubkey::declare_id!("CpkdQmspsaZZ8FVAouQTtTWZkc8eeQ7V3uj7dWz543rZ"); -} - -pub mod account_hash_ignore_slot { - solana_pubkey::declare_id!("SVn36yVApPLYsa8koK3qUcy14zXDnqkNYWyUh1f4oK1"); -} - -pub mod set_exempt_rent_epoch_max { - solana_pubkey::declare_id!("5wAGiy15X1Jb2hkHnPDCM8oB9V42VNA9ftNVFK84dEgv"); -} - -pub mod relax_authority_signer_check_for_lookup_table_creation { - solana_pubkey::declare_id!("FKAcEvNgSY79RpqsPNUV5gDyumopH4cEHqUxyfm8b8Ap"); -} - -pub mod stop_sibling_instruction_search_at_parent { - solana_pubkey::declare_id!("EYVpEP7uzH1CoXzbD6PubGhYmnxRXPeq3PPsm1ba3gpo"); -} - -pub mod vote_state_update_root_fix { - solana_pubkey::declare_id!("G74BkWBzmsByZ1kxHy44H3wjwp5hp7JbrGRuDpco22tY"); -} - -pub mod cap_accounts_data_allocations_per_transaction { - solana_pubkey::declare_id!("9gxu85LYRAcZL38We8MYJ4A9AwgBBPtVBAqebMcT1241"); -} - -pub mod epoch_accounts_hash { - solana_pubkey::declare_id!("5GpmAKxaGsWWbPp4bNXFLJxZVvG92ctxf7jQnzTQjF3n"); -} - -pub mod remove_deprecated_request_unit_ix { - solana_pubkey::declare_id!("EfhYd3SafzGT472tYQDUc4dPd2xdEfKs5fwkowUgVt4W"); -} - -pub mod disable_rehash_for_rent_epoch { - solana_pubkey::declare_id!("DTVTkmw3JSofd8CJVJte8PXEbxNQ2yZijvVr3pe2APPj"); -} - -pub mod increase_tx_account_lock_limit { - solana_pubkey::declare_id!("9LZdXeKGeBV6hRLdxS1rHbHoEUsKqesCC2ZAPTPKJAbK"); -} - -pub mod limit_max_instruction_trace_length { - solana_pubkey::declare_id!("GQALDaC48fEhZGWRj9iL5Q889emJKcj3aCvHF7VCbbF4"); -} - -pub mod check_syscall_outputs_do_not_overlap { - solana_pubkey::declare_id!("3uRVPBpyEJRo1emLCrq38eLRFGcu6uKSpUXqGvU8T7SZ"); -} - -pub mod enable_bpf_loader_set_authority_checked_ix { - solana_pubkey::declare_id!("5x3825XS7M2A3Ekbn5VGGkvFoAg5qrRWkTrY4bARP1GL"); -} - -pub mod enable_alt_bn128_syscall { - solana_pubkey::declare_id!("A16q37opZdQMCbe5qJ6xpBB9usykfv8jZaMkxvZQi4GJ"); -} - -pub mod simplify_alt_bn128_syscall_error_codes { - solana_pubkey::declare_id!("JDn5q3GBeqzvUa7z67BbmVHVdE3EbUAjvFep3weR3jxX"); -} - -pub mod enable_alt_bn128_compression_syscall { - solana_pubkey::declare_id!("EJJewYSddEEtSZHiqugnvhQHiWyZKjkFDQASd7oKSagn"); -} - -pub mod fix_alt_bn128_multiplication_input_length { - solana_pubkey::declare_id!("bn2puAyxUx6JUabAxYdKdJ5QHbNNmKw8dCGuGCyRrFN"); -} - -pub mod enable_program_redeployment_cooldown { - solana_pubkey::declare_id!("J4HFT8usBxpcF63y46t1upYobJgChmKyZPm5uTBRg25Z"); -} - -pub mod commission_updates_only_allowed_in_first_half_of_epoch { - solana_pubkey::declare_id!("noRuG2kzACwgaY7TVmLRnUNPLKNVQE1fb7X55YWBehp"); -} - -pub mod enable_turbine_fanout_experiments { - solana_pubkey::declare_id!("D31EFnLgdiysi84Woo3of4JMu7VmasUS3Z7j9HYXCeLY"); -} - -pub mod disable_turbine_fanout_experiments { - solana_pubkey::declare_id!("Gz1aLrbeQ4Q6PTSafCZcGWZXz91yVRi7ASFzFEr1U4sa"); -} - -pub mod move_serialized_len_ptr_in_cpi { - solana_pubkey::declare_id!("74CoWuBmt3rUVUrCb2JiSTvh6nXyBWUsK4SaMj3CtE3T"); -} - -pub mod update_hashes_per_tick { - solana_pubkey::declare_id!("3uFHb9oKdGfgZGJK9EHaAXN4USvnQtAFC13Fh5gGFS5B"); -} - -pub mod enable_big_mod_exp_syscall { - solana_pubkey::declare_id!("EBq48m8irRKuE7ZnMTLvLg2UuGSqhe8s8oMqnmja1fJw"); -} - -pub mod disable_builtin_loader_ownership_chains { - solana_pubkey::declare_id!("4UDcAfQ6EcA6bdcadkeHpkarkhZGJ7Bpq7wTAiRMjkoi"); -} - -pub mod cap_transaction_accounts_data_size { - solana_pubkey::declare_id!("DdLwVYuvDz26JohmgSbA7mjpJFgX5zP2dkp8qsF2C33V"); -} - -pub mod remove_congestion_multiplier_from_fee_calculation { - solana_pubkey::declare_id!("A8xyMHZovGXFkorFqEmVH2PKGLiBip5JD7jt4zsUWo4H"); -} - -pub mod enable_request_heap_frame_ix { - solana_pubkey::declare_id!("Hr1nUA9b7NJ6eChS26o7Vi8gYYDDwWD3YeBfzJkTbU86"); -} - -pub mod prevent_rent_paying_rent_recipients { - solana_pubkey::declare_id!("Fab5oP3DmsLYCiQZXdjyqT3ukFFPrsmqhXU4WU1AWVVF"); -} - -pub mod delay_visibility_of_program_deployment { - solana_pubkey::declare_id!("GmuBvtFb2aHfSfMXpuFeWZGHyDeCLPS79s48fmCWCfM5"); -} - -pub mod apply_cost_tracker_during_replay { - solana_pubkey::declare_id!("2ry7ygxiYURULZCrypHhveanvP5tzZ4toRwVp89oCNSj"); -} -pub mod bpf_account_data_direct_mapping { - solana_pubkey::declare_id!("AjX3A4Nv2rzUuATEUWLP4rrBaBropyUnHxEvFDj1dKbx"); -} - -pub mod add_set_tx_loaded_accounts_data_size_instruction { - solana_pubkey::declare_id!("G6vbf1UBok8MWb8m25ex86aoQHeKTzDKzuZADHkShqm6"); -} - -pub mod switch_to_new_elf_parser { - solana_pubkey::declare_id!("Cdkc8PPTeTNUPoZEfCY5AyetUrEdkZtNPMgz58nqyaHD"); -} - -pub mod round_up_heap_size { - solana_pubkey::declare_id!("CE2et8pqgyQMP2mQRg3CgvX8nJBKUArMu3wfiQiQKY1y"); -} - -pub mod remove_bpf_loader_incorrect_program_id { - solana_pubkey::declare_id!("2HmTkCj9tXuPE4ueHzdD7jPeMf9JGCoZh5AsyoATiWEe"); -} - -pub mod include_loaded_accounts_data_size_in_fee_calculation { - solana_pubkey::declare_id!("EaQpmC6GtRssaZ3PCUM5YksGqUdMLeZ46BQXYtHYakDS"); -} - -pub mod native_programs_consume_cu { - solana_pubkey::declare_id!("8pgXCMNXC8qyEFypuwpXyRxLXZdpM4Qo72gJ6k87A6wL"); -} - -pub mod simplify_writable_program_account_check { - solana_pubkey::declare_id!("5ZCcFAzJ1zsFKe1KSZa9K92jhx7gkcKj97ci2DBo1vwj"); -} - -pub mod stop_truncating_strings_in_syscalls { - solana_pubkey::declare_id!("16FMCmgLzCNNz6eTwGanbyN2ZxvTBSLuQ6DZhgeMshg"); -} - -pub mod clean_up_delegation_errors { - solana_pubkey::declare_id!("Bj2jmUsM2iRhfdLLDSTkhM5UQRQvQHm57HSmPibPtEyu"); -} - -pub mod vote_state_add_vote_latency { - solana_pubkey::declare_id!("7axKe5BTYBDD87ftzWbk5DfzWMGyRvqmWTduuo22Yaqy"); -} - -pub mod checked_arithmetic_in_fee_validation { - solana_pubkey::declare_id!("5Pecy6ie6XGm22pc9d4P9W5c31BugcFBuy6hsP2zkETv"); -} - -pub mod last_restart_slot_sysvar { - solana_pubkey::declare_id!("HooKD5NC9QNxk25QuzCssB8ecrEzGt6eXEPBUxWp1LaR"); -} - -pub mod reduce_stake_warmup_cooldown { - solana_pubkey::declare_id!("GwtDQBghCTBgmX2cpEGNPxTEBUTQRaDMGTr5qychdGMj"); -} - -pub mod revise_turbine_epoch_stakes { - solana_pubkey::declare_id!("BTWmtJC8U5ZLMbBUUA1k6As62sYjPEjAiNAT55xYGdJU"); -} - -pub mod enable_poseidon_syscall { - solana_pubkey::declare_id!("FL9RsQA6TVUoh5xJQ9d936RHSebA1NLQqe3Zv9sXZRpr"); -} - -pub mod timely_vote_credits { - solana_pubkey::declare_id!("tvcF6b1TRz353zKuhBjinZkKzjmihXmBAHJdjNYw1sQ"); -} - -pub mod remaining_compute_units_syscall_enabled { - solana_pubkey::declare_id!("5TuppMutoyzhUSfuYdhgzD47F92GL1g89KpCZQKqedxP"); -} - -pub mod enable_loader_v4 { - solana_pubkey::declare_id!("8Cb77yHjPWe9wuWUfXeh6iszFGCDGNCoFk3tprViYHNm"); -} - -pub mod disable_new_loader_v3_deployments { - solana_pubkey::declare_id!("EmhbpdVtZ2hWRGFWBDjn2i3SJD8Z36z4mpMcZJEnebnP"); -} - -pub mod require_rent_exempt_split_destination { - solana_pubkey::declare_id!("D2aip4BBr8NPWtU9vLrwrBvbuaQ8w1zV38zFLxx4pfBV"); -} - -pub mod better_error_codes_for_tx_lamport_check { - solana_pubkey::declare_id!("Ffswd3egL3tccB6Rv3XY6oqfdzn913vUcjCSnpvCKpfx"); -} - -pub mod update_hashes_per_tick2 { - solana_pubkey::declare_id!("EWme9uFqfy1ikK1jhJs8fM5hxWnK336QJpbscNtizkTU"); -} - -pub mod update_hashes_per_tick3 { - solana_pubkey::declare_id!("8C8MCtsab5SsfammbzvYz65HHauuUYdbY2DZ4sznH6h5"); -} - -pub mod update_hashes_per_tick4 { - solana_pubkey::declare_id!("8We4E7DPwF2WfAN8tRTtWQNhi98B99Qpuj7JoZ3Aikgg"); -} - -pub mod update_hashes_per_tick5 { - solana_pubkey::declare_id!("BsKLKAn1WM4HVhPRDsjosmqSg2J8Tq5xP2s2daDS6Ni4"); -} - -pub mod update_hashes_per_tick6 { - solana_pubkey::declare_id!("FKu1qYwLQSiehz644H6Si65U5ZQ2cp9GxsyFUfYcuADv"); -} - -pub mod validate_fee_collector_account { - solana_pubkey::declare_id!("prpFrMtgNmzaNzkPJg9o753fVvbHKqNrNTm76foJ2wm"); -} - -pub mod disable_rent_fees_collection { - solana_pubkey::declare_id!("CJzY83ggJHqPGDq8VisV3U91jDJLuEaALZooBrXtnnLU"); -} - -pub mod enable_zk_transfer_with_fee { - solana_pubkey::declare_id!("zkNLP7EQALfC1TYeB3biDU7akDckj8iPkvh9y2Mt2K3"); -} - -pub mod drop_legacy_shreds { - solana_pubkey::declare_id!("GV49KKQdBNaiv2pgqhS2Dy3GWYJGXMTVYbYkdk91orRy"); -} - -pub mod allow_commission_decrease_at_any_time { - solana_pubkey::declare_id!("decoMktMcnmiq6t3u7g5BfgcQu91nKZr6RvMYf9z1Jb"); -} - -pub mod add_new_reserved_account_keys { - solana_pubkey::declare_id!("8U4skmMVnF6k2kMvrWbQuRUT3qQSiTYpSjqmhmgfthZu"); -} - -pub mod consume_blockstore_duplicate_proofs { - solana_pubkey::declare_id!("6YsBCejwK96GZCkJ6mkZ4b68oP63z2PLoQmWjC7ggTqZ"); -} - -pub mod index_erasure_conflict_duplicate_proofs { - solana_pubkey::declare_id!("dupPajaLy2SSn8ko42aZz4mHANDNrLe8Nw8VQgFecLa"); -} - -pub mod merkle_conflict_duplicate_proofs { - solana_pubkey::declare_id!("mrkPjRg79B2oK2ZLgd7S3AfEJaX9B6gAF3H9aEykRUS"); -} - -pub mod disable_bpf_loader_instructions { - solana_pubkey::declare_id!("7WeS1vfPRgeeoXArLh7879YcB9mgE9ktjPDtajXeWfXn"); -} - -pub mod enable_zk_proof_from_account { - solana_pubkey::declare_id!("zkiTNuzBKxrCLMKehzuQeKZyLtX2yvFcEKMML8nExU8"); -} - -pub mod cost_model_requested_write_lock_cost { - solana_pubkey::declare_id!("wLckV1a64ngtcKPRGU4S4grVTestXjmNjxBjaKZrAcn"); -} - -pub mod enable_gossip_duplicate_proof_ingestion { - solana_pubkey::declare_id!("FNKCMBzYUdjhHyPdsKG2LSmdzH8TCHXn3ytj8RNBS4nG"); -} - -pub mod chained_merkle_conflict_duplicate_proofs { - solana_pubkey::declare_id!("chaie9S2zVfuxJKNRGkyTDokLwWxx6kD2ZLsqQHaDD8"); -} - -pub mod enable_chained_merkle_shreds { - solana_pubkey::declare_id!("7uZBkJXJ1HkuP6R3MJfZs7mLwymBcDbKdqbF51ZWLier"); -} - -pub mod remove_rounding_in_fee_calculation { - solana_pubkey::declare_id!("BtVN7YjDzNE6Dk7kTT7YTDgMNUZTNgiSJgsdzAeTg2jF"); -} - -pub mod enable_tower_sync_ix { - solana_pubkey::declare_id!("tSynMCspg4xFiCj1v3TDb4c7crMR5tSBhLz4sF7rrNA"); -} - -pub mod deprecate_unused_legacy_vote_plumbing { - solana_pubkey::declare_id!("6Uf8S75PVh91MYgPQSHnjRAPQq6an5BDv9vomrCwDqLe"); -} - -pub mod reward_full_priority_fee { - solana_pubkey::declare_id!("3opE3EzAKnUftUDURkzMgwpNgimBAypW1mNDYH4x4Zg7"); -} - -pub mod get_sysvar_syscall_enabled { - solana_pubkey::declare_id!("CLCoTADvV64PSrnR6QXty6Fwrt9Xc6EdxSJE4wLRePjq"); -} - -pub mod abort_on_invalid_curve { - solana_pubkey::declare_id!("FuS3FPfJDKSNot99ECLXtp3rueq36hMNStJkPJwWodLh"); -} - -pub mod migrate_feature_gate_program_to_core_bpf { - solana_pubkey::declare_id!("4eohviozzEeivk1y9UbrnekbAFMDQyJz5JjA9Y6gyvky"); -} - -pub mod vote_only_full_fec_sets { - solana_pubkey::declare_id!("ffecLRhhakKSGhMuc6Fz2Lnfq4uT9q3iu9ZsNaPLxPc"); -} - -pub mod migrate_config_program_to_core_bpf { - solana_pubkey::declare_id!("2Fr57nzzkLYXW695UdDxDeR5fhnZWSttZeZYemrnpGFV"); -} - -pub mod enable_get_epoch_stake_syscall { - solana_pubkey::declare_id!("FKe75t4LXxGaQnVHdUKM6DSFifVVraGZ8LyNo7oPwy1Z"); -} - -pub mod migrate_address_lookup_table_program_to_core_bpf { - solana_pubkey::declare_id!("C97eKZygrkU4JxJsZdjgbUY7iQR7rKTr4NyDWo2E5pRm"); -} - -pub mod zk_elgamal_proof_program_enabled { - solana_pubkey::declare_id!("zkhiy5oLowR7HY4zogXjCjeMXyruLqBwSWH21qcFtnv"); -} - -pub mod verify_retransmitter_signature { - solana_pubkey::declare_id!("BZ5g4hRbu5hLQQBdPyo2z9icGyJ8Khiyj3QS6dhWijTb"); -} - -pub mod move_stake_and_move_lamports_ixs { - solana_pubkey::declare_id!("7bTK6Jis8Xpfrs8ZoUfiMDPazTcdPcTWheZFJTA5Z6X4"); -} - -pub mod ed25519_precompile_verify_strict { - solana_pubkey::declare_id!("ed9tNscbWLYBooxWA7FE2B5KHWs8A6sxfY8EzezEcoo"); -} - -pub mod vote_only_retransmitter_signed_fec_sets { - solana_pubkey::declare_id!("RfEcA95xnhuwooVAhUUksEJLZBF7xKCLuqrJoqk4Zph"); -} - -pub mod move_precompile_verification_to_svm { - solana_pubkey::declare_id!("9ypxGLzkMxi89eDerRKXWDXe44UY2z4hBig4mDhNq5Dp"); -} - -pub mod enable_transaction_loading_failure_fees { - solana_pubkey::declare_id!("PaymEPK2oqwT9TXAVfadjztH2H6KfLEB9Hhd5Q5frvP"); -} - -pub mod enable_turbine_extended_fanout_experiments { - solana_pubkey::declare_id!("BZn14Liea52wtBwrXUxTv6vojuTTmfc7XGEDTXrvMD7b"); -} - -pub mod deprecate_legacy_vote_ixs { - solana_pubkey::declare_id!("depVvnQ2UysGrhwdiwU42tCadZL8GcBb1i2GYhMopQv"); -} - -pub mod disable_sbpf_v0_execution { - solana_pubkey::declare_id!("TestFeature11111111111111111111111111111111"); -} - -pub mod reenable_sbpf_v0_execution { - solana_pubkey::declare_id!("TestFeature21111111111111111111111111111111"); -} - -pub mod enable_sbpf_v1_deployment_and_execution { - solana_pubkey::declare_id!("JE86WkYvTrzW8HgNmrHY7dFYpCmSptUpKupbo2AdQ9cG"); -} - -pub mod enable_sbpf_v2_deployment_and_execution { - solana_pubkey::declare_id!("F6UVKh1ujTEFK3en2SyAL3cdVnqko1FVEXWhmdLRu6WP"); -} - -pub mod enable_sbpf_v3_deployment_and_execution { - solana_pubkey::declare_id!("C8XZNs1bfzaiT3YDeXZJ7G5swQWQv7tVzDnCxtHvnSpw"); -} - -pub mod remove_accounts_executable_flag_checks { - solana_pubkey::declare_id!("FfgtauHUWKeXTzjXkua9Px4tNGBFHKZ9WaigM5VbbzFx"); -} - -pub mod lift_cpi_caller_restriction { - solana_pubkey::declare_id!("HcW8ZjBezYYgvcbxNJwqv1t484Y2556qJsfNDWvJGZRH"); -} - -pub mod disable_account_loader_special_case { - solana_pubkey::declare_id!("EQUMpNFr7Nacb1sva56xn1aLfBxppEoSBH8RRVdkcD1x"); -} - -pub mod enable_secp256r1_precompile { - solana_pubkey::declare_id!("srremy31J5Y25FrAApwVb9kZcfXbusYMMsvTK9aWv5q"); -} - -pub mod accounts_lt_hash { - solana_pubkey::declare_id!("LtHaSHHsUge7EWTPVrmpuexKz6uVHZXZL6cgJa7W7Zn"); -} - -pub mod snapshots_lt_hash { - solana_pubkey::declare_id!("LTsNAP8h1voEVVToMNBNqoiNQex4aqfUrbFhRH3mSQ2"); -} - -pub mod remove_accounts_delta_hash { - solana_pubkey::declare_id!("LTdLt9Ycbyoipz5fLysCi1NnDnASsZfmJLJXts5ZxZz"); -} - -pub mod migrate_stake_program_to_core_bpf { - solana_pubkey::declare_id!("6M4oQ6eXneVhtLoiAr4yRYQY43eVLjrKbiDZDJc892yk"); -} - -pub mod deplete_cu_meter_on_vm_failure { - solana_pubkey::declare_id!("B7H2caeia4ZFcpE3QcgMqbiWiBtWrdBRBSJ1DY6Ktxbq"); -} - -pub mod reserve_minimal_cus_for_builtin_instructions { - solana_pubkey::declare_id!("C9oAhLxDBm3ssWtJx1yBGzPY55r2rArHmN1pbQn6HogH"); -} - -pub mod raise_block_limits_to_50m { - solana_pubkey::declare_id!("5oMCU3JPaFLr8Zr4ct7yFA7jdk6Mw1RmB8K4u9ZbS42z"); -} - -pub mod drop_unchained_merkle_shreds { - solana_pubkey::declare_id!("3A9WtMU4aHuryD3VN7SFKdfXto8HStLb1Jj6HjkgfnGL"); -} - -pub mod relax_intrabatch_account_locks { - solana_pubkey::declare_id!("EbAhnReKK8Sf88CvAfAXbgKji8DV48rsp4q2sgHqgWef"); -} - -pub mod create_slashing_program { - solana_pubkey::declare_id!("sProgVaNWkYdP2eTRAy1CPrgb3b9p8yXCASrPEqo6VJ"); -} - -pub mod disable_partitioned_rent_collection { - solana_pubkey::declare_id!("2B2SBNbUcr438LtGXNcJNBP2GBSxjx81F945SdSkUSfC"); -} - -pub mod enable_vote_address_leader_schedule { - solana_pubkey::declare_id!("5JsG4NWH8Jbrqdd8uL6BNwnyZK3dQSoieRXG5vmofj9y"); -} - -lazy_static! { - /// Map of feature identifiers to user-visible description - pub static ref FEATURE_NAMES: AHashMap = [ - (secp256k1_program_enabled::id(), "secp256k1 program"), - (deprecate_rewards_sysvar::id(), "deprecate unused rewards sysvar"), - (pico_inflation::id(), "pico inflation"), - (full_inflation::devnet_and_testnet::id(), "full inflation on devnet and testnet"), - (spl_token_v2_multisig_fix::id(), "spl-token multisig fix"), - (no_overflow_rent_distribution::id(), "no overflow rent distribution"), - (filter_stake_delegation_accounts::id(), "filter stake_delegation_accounts #14062"), - (require_custodian_for_locked_stake_authorize::id(), "require custodian to authorize withdrawer change for locked stake"), - (spl_token_v2_self_transfer_fix::id(), "spl-token self-transfer fix"), - (full_inflation::mainnet::certusone::enable::id(), "full inflation enabled by Certus One"), - (full_inflation::mainnet::certusone::vote::id(), "community vote allowing Certus One to enable full inflation"), - (warp_timestamp_again::id(), "warp timestamp again, adjust bounding to 25% fast 80% slow #15204"), - (check_init_vote_data::id(), "check initialized Vote data"), - (secp256k1_recover_syscall_enabled::id(), "secp256k1_recover syscall"), - (system_transfer_zero_check::id(), "perform all checks for transfers of 0 lamports"), - (blake3_syscall_enabled::id(), "blake3 syscall"), - (dedupe_config_program_signers::id(), "dedupe config program signers"), - (verify_tx_signatures_len::id(), "prohibit extra transaction signatures"), - (vote_stake_checked_instructions::id(), "vote/state program checked instructions #18345"), - (rent_for_sysvars::id(), "collect rent from accounts owned by sysvars"), - (libsecp256k1_0_5_upgrade_enabled::id(), "upgrade libsecp256k1 to v0.5.0"), - (tx_wide_compute_cap::id(), "transaction wide compute cap"), - (spl_token_v2_set_authority_fix::id(), "spl-token set_authority fix"), - (merge_nonce_error_into_system_error::id(), "merge NonceError into SystemError"), - (disable_fees_sysvar::id(), "disable fees sysvar"), - (stake_merge_with_unmatched_credits_observed::id(), "allow merging active stakes with unmatched credits_observed #18985"), - (zk_token_sdk_enabled::id(), "enable Zk Token proof program and syscalls"), - (curve25519_syscall_enabled::id(), "enable curve25519 syscalls"), - (versioned_tx_message_enabled::id(), "enable versioned transaction message processing"), - (libsecp256k1_fail_on_bad_count::id(), "fail libsecp256k1_verify if count appears wrong"), - (libsecp256k1_fail_on_bad_count2::id(), "fail libsecp256k1_verify if count appears wrong"), - (instructions_sysvar_owned_by_sysvar::id(), "fix owner for instructions sysvar"), - (stake_program_advance_activating_credits_observed::id(), "Enable advancing credits observed for activation epoch #19309"), - (credits_auto_rewind::id(), "Auto rewind stake's credits_observed if (accidental) vote recreation is detected #22546"), - (demote_program_write_locks::id(), "demote program write locks to readonly, except when upgradeable loader present #19593 #20265"), - (ed25519_program_enabled::id(), "enable builtin ed25519 signature verify program"), - (return_data_syscall_enabled::id(), "enable sol_{set,get}_return_data syscall"), - (reduce_required_deploy_balance::id(), "reduce required payer balance for program deploys"), - (sol_log_data_syscall_enabled::id(), "enable sol_log_data syscall"), - (stakes_remove_delegation_if_inactive::id(), "remove delegations from stakes cache when inactive"), - (do_support_realloc::id(), "support account data reallocation"), - (prevent_calling_precompiles_as_programs::id(), "prevent calling precompiles as programs"), - (optimize_epoch_boundary_updates::id(), "optimize epoch boundary updates"), - (remove_native_loader::id(), "remove support for the native loader"), - (send_to_tpu_vote_port::id(), "send votes to the tpu vote port"), - (requestable_heap_size::id(), "Requestable heap frame size"), - (disable_fee_calculator::id(), "deprecate fee calculator"), - (add_compute_budget_program::id(), "Add compute_budget_program"), - (nonce_must_be_writable::id(), "nonce must be writable"), - (spl_token_v3_3_0_release::id(), "spl-token v3.3.0 release"), - (leave_nonce_on_success::id(), "leave nonce as is on success"), - (reject_empty_instruction_without_program::id(), "fail instructions which have native_loader as program_id directly"), - (fixed_memcpy_nonoverlapping_check::id(), "use correct check for nonoverlapping regions in memcpy syscall"), - (reject_non_rent_exempt_vote_withdraws::id(), "fail vote withdraw instructions which leave the account non-rent-exempt"), - (evict_invalid_stakes_cache_entries::id(), "evict invalid stakes cache entries on epoch boundaries"), - (allow_votes_to_directly_update_vote_state::id(), "enable direct vote state update"), - (max_tx_account_locks::id(), "enforce max number of locked accounts per transaction"), - (require_rent_exempt_accounts::id(), "require all new transaction accounts with data to be rent-exempt"), - (filter_votes_outside_slot_hashes::id(), "filter vote slots older than the slot hashes history"), - (update_syscall_base_costs::id(), "update syscall base costs"), - (stake_deactivate_delinquent_instruction::id(), "enable the deactivate delinquent stake instruction #23932"), - (vote_withdraw_authority_may_change_authorized_voter::id(), "vote account withdraw authority may change the authorized voter #22521"), - (spl_associated_token_account_v1_0_4::id(), "SPL Associated Token Account Program release version 1.0.4, tied to token 3.3.0 #22648"), - (reject_vote_account_close_unless_zero_credit_epoch::id(), "fail vote account withdraw to 0 unless account earned 0 credits in last completed epoch"), - (add_get_processed_sibling_instruction_syscall::id(), "add add_get_processed_sibling_instruction_syscall"), - (bank_transaction_count_fix::id(), "fixes Bank::transaction_count to include all committed transactions, not just successful ones"), - (disable_bpf_deprecated_load_instructions::id(), "disable ldabs* and ldind* SBF instructions"), - (disable_bpf_unresolved_symbols_at_runtime::id(), "disable reporting of unresolved SBF symbols at runtime"), - (record_instruction_in_transaction_context_push::id(), "move the CPI stack overflow check to the end of push"), - (syscall_saturated_math::id(), "syscalls use saturated math"), - (check_physical_overlapping::id(), "check physical overlapping regions"), - (limit_secp256k1_recovery_id::id(), "limit secp256k1 recovery id"), - (disable_deprecated_loader::id(), "disable the deprecated BPF loader"), - (check_slice_translation_size::id(), "check size when translating slices"), - (stake_split_uses_rent_sysvar::id(), "stake split instruction uses rent sysvar"), - (add_get_minimum_delegation_instruction_to_stake_program::id(), "add GetMinimumDelegation instruction to stake program"), - (error_on_syscall_bpf_function_hash_collisions::id(), "error on bpf function hash collisions"), - (reject_callx_r10::id(), "Reject bpf callx r10 instructions"), - (drop_redundant_turbine_path::id(), "drop redundant turbine path"), - (executables_incur_cpi_data_cost::id(), "Executables incur CPI data costs"), - (fix_recent_blockhashes::id(), "stop adding hashes for skipped slots to recent blockhashes"), - (update_rewards_from_cached_accounts::id(), "update rewards from cached accounts"), - (enable_partitioned_epoch_reward::id(), "enable partitioned rewards at epoch boundary #32166"), - (spl_token_v3_4_0::id(), "SPL Token Program version 3.4.0 release #24740"), - (spl_associated_token_account_v1_1_0::id(), "SPL Associated Token Account Program version 1.1.0 release #24741"), - (default_units_per_instruction::id(), "Default max tx-wide compute units calculated per instruction"), - (stake_allow_zero_undelegated_amount::id(), "Allow zero-lamport undelegated amount for initialized stakes #24670"), - (require_static_program_ids_in_transaction::id(), "require static program ids in versioned transactions"), - (stake_raise_minimum_delegation_to_1_sol::id(), "Raise minimum stake delegation to 1.0 SOL #24357"), - (stake_minimum_delegation_for_rewards::id(), "stakes must be at least the minimum delegation to earn rewards"), - (add_set_compute_unit_price_ix::id(), "add compute budget ix for setting a compute unit price"), - (disable_deploy_of_alloc_free_syscall::id(), "disable new deployments of deprecated sol_alloc_free_ syscall"), - (include_account_index_in_rent_error::id(), "include account index in rent tx error #25190"), - (add_shred_type_to_shred_seed::id(), "add shred-type to shred seed #25556"), - (warp_timestamp_with_a_vengeance::id(), "warp timestamp again, adjust bounding to 150% slow #25666"), - (separate_nonce_from_blockhash::id(), "separate durable nonce and blockhash domains #25744"), - (enable_durable_nonce::id(), "enable durable nonce #25744"), - (vote_state_update_credit_per_dequeue::id(), "Calculate vote credits for VoteStateUpdate per vote dequeue to match credit awards for Vote instruction"), - (quick_bail_on_panic::id(), "quick bail on panic"), - (nonce_must_be_authorized::id(), "nonce must be authorized"), - (nonce_must_be_advanceable::id(), "durable nonces must be advanceable"), - (vote_authorize_with_seed::id(), "An instruction you can use to change a vote accounts authority when the current authority is a derived key #25860"), - (preserve_rent_epoch_for_rent_exempt_accounts::id(), "preserve rent epoch for rent exempt accounts #26479"), - (enable_bpf_loader_extend_program_ix::id(), "enable bpf upgradeable loader ExtendProgram instruction #25234"), - (skip_rent_rewrites::id(), "skip rewriting rent exempt accounts during rent collection #26491"), - (enable_early_verification_of_account_modifications::id(), "enable early verification of account modifications #25899"), - (disable_rehash_for_rent_epoch::id(), "on accounts hash calculation, do not try to rehash accounts #28934"), - (account_hash_ignore_slot::id(), "ignore slot when calculating an account hash #28420"), - (set_exempt_rent_epoch_max::id(), "set rent epoch to Epoch::MAX for rent-exempt accounts #28683"), - (on_load_preserve_rent_epoch_for_rent_exempt_accounts::id(), "on bank load account, do not try to fix up rent_epoch #28541"), - (prevent_crediting_accounts_that_end_rent_paying::id(), "prevent crediting rent paying accounts #26606"), - (cap_bpf_program_instruction_accounts::id(), "enforce max number of accounts per bpf program instruction #26628"), - (loosen_cpi_size_restriction::id(), "loosen cpi size restrictions #26641"), - (use_default_units_in_fee_calculation::id(), "use default units per instruction in fee calculation #26785"), - (compact_vote_state_updates::id(), "Compact vote state updates to lower block size"), - (incremental_snapshot_only_incremental_hash_calculation::id(), "only hash accounts in incremental snapshot during incremental snapshot creation #26799"), - (disable_cpi_setting_executable_and_rent_epoch::id(), "disable setting is_executable and_rent_epoch in CPI #26987"), - (relax_authority_signer_check_for_lookup_table_creation::id(), "relax authority signer check for lookup table creation #27205"), - (stop_sibling_instruction_search_at_parent::id(), "stop the search in get_processed_sibling_instruction when the parent instruction is reached #27289"), - (vote_state_update_root_fix::id(), "fix root in vote state updates #27361"), - (cap_accounts_data_allocations_per_transaction::id(), "cap accounts data allocations per transaction #27375"), - (epoch_accounts_hash::id(), "enable epoch accounts hash calculation #27539"), - (remove_deprecated_request_unit_ix::id(), "remove support for RequestUnitsDeprecated instruction #27500"), - (increase_tx_account_lock_limit::id(), "increase tx account lock limit to 128 #27241"), - (limit_max_instruction_trace_length::id(), "limit max instruction trace length #27939"), - (check_syscall_outputs_do_not_overlap::id(), "check syscall outputs do_not overlap #28600"), - (enable_bpf_loader_set_authority_checked_ix::id(), "enable bpf upgradeable loader SetAuthorityChecked instruction #28424"), - (enable_alt_bn128_syscall::id(), "add alt_bn128 syscalls #27961"), - (simplify_alt_bn128_syscall_error_codes::id(), "simplify alt_bn128 syscall error codes SIMD-0129"), - (enable_program_redeployment_cooldown::id(), "enable program redeployment cooldown #29135"), - (commission_updates_only_allowed_in_first_half_of_epoch::id(), "validator commission updates are only allowed in the first half of an epoch #29362"), - (enable_turbine_fanout_experiments::id(), "enable turbine fanout experiments #29393"), - (disable_turbine_fanout_experiments::id(), "disable turbine fanout experiments #29393"), - (move_serialized_len_ptr_in_cpi::id(), "cpi ignore serialized_len_ptr #29592"), - (update_hashes_per_tick::id(), "Update desired hashes per tick on epoch boundary"), - (enable_big_mod_exp_syscall::id(), "add big_mod_exp syscall #28503"), - (disable_builtin_loader_ownership_chains::id(), "disable builtin loader ownership chains #29956"), - (cap_transaction_accounts_data_size::id(), "cap transaction accounts data size up to a limit #27839"), - (remove_congestion_multiplier_from_fee_calculation::id(), "Remove congestion multiplier from transaction fee calculation #29881"), - (enable_request_heap_frame_ix::id(), "Enable transaction to request heap frame using compute budget instruction #30076"), - (prevent_rent_paying_rent_recipients::id(), "prevent recipients of rent rewards from ending in rent-paying state #30151"), - (delay_visibility_of_program_deployment::id(), "delay visibility of program upgrades #30085"), - (apply_cost_tracker_during_replay::id(), "apply cost tracker to blocks during replay #29595"), - (add_set_tx_loaded_accounts_data_size_instruction::id(), "add compute budget instruction for setting account data size per transaction #30366"), - (switch_to_new_elf_parser::id(), "switch to new ELF parser #30497"), - (round_up_heap_size::id(), "round up heap size when calculating heap cost #30679"), - (remove_bpf_loader_incorrect_program_id::id(), "stop incorrectly throwing IncorrectProgramId in bpf_loader #30747"), - (include_loaded_accounts_data_size_in_fee_calculation::id(), "include transaction loaded accounts data size in base fee calculation #30657"), - (native_programs_consume_cu::id(), "Native program should consume compute units #30620"), - (simplify_writable_program_account_check::id(), "Simplify checks performed for writable upgradeable program accounts #30559"), - (stop_truncating_strings_in_syscalls::id(), "Stop truncating strings in syscalls #31029"), - (clean_up_delegation_errors::id(), "Return InsufficientDelegation instead of InsufficientFunds or InsufficientStake where applicable #31206"), - (vote_state_add_vote_latency::id(), "replace Lockout with LandedVote (including vote latency) in vote state #31264"), - (checked_arithmetic_in_fee_validation::id(), "checked arithmetic in fee validation #31273"), - (bpf_account_data_direct_mapping::id(), "use memory regions to map account data into the rbpf vm instead of copying the data"), - (last_restart_slot_sysvar::id(), "enable new sysvar last_restart_slot"), - (reduce_stake_warmup_cooldown::id(), "reduce stake warmup cooldown from 25% to 9%"), - (revise_turbine_epoch_stakes::id(), "revise turbine epoch stakes"), - (enable_poseidon_syscall::id(), "Enable Poseidon syscall"), - (timely_vote_credits::id(), "use timeliness of votes in determining credits to award"), - (remaining_compute_units_syscall_enabled::id(), "enable the remaining_compute_units syscall"), - (enable_loader_v4::id(), "Enable Loader-v4 SIMD-0167"), - (disable_new_loader_v3_deployments::id(), "Disable new loader-v3 deployments SIMD-0167"), - (require_rent_exempt_split_destination::id(), "Require stake split destination account to be rent exempt"), - (better_error_codes_for_tx_lamport_check::id(), "better error codes for tx lamport check #33353"), - (enable_alt_bn128_compression_syscall::id(), "add alt_bn128 compression syscalls"), - (update_hashes_per_tick2::id(), "Update desired hashes per tick to 2.8M"), - (update_hashes_per_tick3::id(), "Update desired hashes per tick to 4.4M"), - (update_hashes_per_tick4::id(), "Update desired hashes per tick to 7.6M"), - (update_hashes_per_tick5::id(), "Update desired hashes per tick to 9.2M"), - (update_hashes_per_tick6::id(), "Update desired hashes per tick to 10M"), - (validate_fee_collector_account::id(), "validate fee collector account #33888"), - (disable_rent_fees_collection::id(), "Disable rent fees collection #33945"), - (enable_zk_transfer_with_fee::id(), "enable Zk Token proof program transfer with fee"), - (drop_legacy_shreds::id(), "drops legacy shreds #34328"), - (allow_commission_decrease_at_any_time::id(), "Allow commission decrease at any time in epoch #33843"), - (consume_blockstore_duplicate_proofs::id(), "consume duplicate proofs from blockstore in consensus #34372"), - (add_new_reserved_account_keys::id(), "add new unwritable reserved accounts #34899"), - (index_erasure_conflict_duplicate_proofs::id(), "generate duplicate proofs for index and erasure conflicts #34360"), - (merkle_conflict_duplicate_proofs::id(), "generate duplicate proofs for merkle root conflicts #34270"), - (disable_bpf_loader_instructions::id(), "disable bpf loader management instructions #34194"), - (enable_zk_proof_from_account::id(), "Enable zk token proof program to read proof from accounts instead of instruction data #34750"), - (curve25519_restrict_msm_length::id(), "restrict curve25519 multiscalar multiplication vector lengths #34763"), - (cost_model_requested_write_lock_cost::id(), "cost model uses number of requested write locks #34819"), - (enable_gossip_duplicate_proof_ingestion::id(), "enable gossip duplicate proof ingestion #32963"), - (enable_chained_merkle_shreds::id(), "Enable chained Merkle shreds #34916"), - (remove_rounding_in_fee_calculation::id(), "Removing unwanted rounding in fee calculation #34982"), - (deprecate_unused_legacy_vote_plumbing::id(), "Deprecate unused legacy vote tx plumbing"), - (enable_tower_sync_ix::id(), "Enable tower sync vote instruction"), - (chained_merkle_conflict_duplicate_proofs::id(), "generate duplicate proofs for chained merkle root conflicts"), - (reward_full_priority_fee::id(), "Reward full priority fee to validators #34731"), - (abort_on_invalid_curve::id(), "Abort when elliptic curve syscalls invoked on invalid curve id SIMD-0137"), - (get_sysvar_syscall_enabled::id(), "Enable syscall for fetching Sysvar bytes #615"), - (migrate_feature_gate_program_to_core_bpf::id(), "Migrate Feature Gate program to Core BPF (programify) #1003"), - (vote_only_full_fec_sets::id(), "vote only full fec sets"), - (migrate_config_program_to_core_bpf::id(), "Migrate Config program to Core BPF #1378"), - (enable_get_epoch_stake_syscall::id(), "Enable syscall: sol_get_epoch_stake #884"), - (migrate_address_lookup_table_program_to_core_bpf::id(), "Migrate Address Lookup Table program to Core BPF #1651"), - (zk_elgamal_proof_program_enabled::id(), "Enable ZkElGamalProof program SIMD-0153"), - (verify_retransmitter_signature::id(), "Verify retransmitter signature #1840"), - (move_stake_and_move_lamports_ixs::id(), "Enable MoveStake and MoveLamports stake program instructions #1610"), - (ed25519_precompile_verify_strict::id(), "Use strict verification in ed25519 precompile SIMD-0152"), - (vote_only_retransmitter_signed_fec_sets::id(), "vote only on retransmitter signed fec sets"), - (move_precompile_verification_to_svm::id(), "SIMD-0159: Move precompile verification into SVM"), - (enable_transaction_loading_failure_fees::id(), "Enable fees for some additional transaction failures SIMD-0082"), - (enable_turbine_extended_fanout_experiments::id(), "enable turbine extended fanout experiments #"), - (deprecate_legacy_vote_ixs::id(), "Deprecate legacy vote instructions"), - (partitioned_epoch_rewards_superfeature::id(), "replaces enable_partitioned_epoch_reward to enable partitioned rewards at epoch boundary SIMD-0118"), - (disable_sbpf_v0_execution::id(), "Disables execution of SBPFv1 programs SIMD-0161"), - (reenable_sbpf_v0_execution::id(), "Re-enables execution of SBPFv1 programs"), - (enable_sbpf_v1_deployment_and_execution::id(), "Enables deployment and execution of SBPFv1 programs SIMD-0161"), - (enable_sbpf_v2_deployment_and_execution::id(), "Enables deployment and execution of SBPFv2 programs SIMD-0161"), - (enable_sbpf_v3_deployment_and_execution::id(), "Enables deployment and execution of SBPFv3 programs SIMD-0161"), - (remove_accounts_executable_flag_checks::id(), "Remove checks of accounts is_executable flag SIMD-0162"), - (lift_cpi_caller_restriction::id(), "Lift the restriction in CPI that the caller must have the callee as an instruction account #2202"), - (disable_account_loader_special_case::id(), "Disable account loader special case #3513"), - (accounts_lt_hash::id(), "enables lattice-based accounts hash SIMD-0215"), - (snapshots_lt_hash::id(), "snapshots use lattice-based accounts hash SIMD-0220"), - (remove_accounts_delta_hash::id(), "removes accounts delta hash SIMD-0223"), - (enable_secp256r1_precompile::id(), "Enable secp256r1 precompile SIMD-0075"), - (migrate_stake_program_to_core_bpf::id(), "Migrate Stake program to Core BPF SIMD-0196 #3655"), - (deplete_cu_meter_on_vm_failure::id(), "Deplete compute meter for vm errors SIMD-0182 #3993"), - (reserve_minimal_cus_for_builtin_instructions::id(), "Reserve minimal CUs for builtin instructions SIMD-170 #2562"), - (raise_block_limits_to_50m::id(), "Raise block limit to 50M SIMD-0207"), - (fix_alt_bn128_multiplication_input_length::id(), "fix alt_bn128 multiplication input length SIMD-0222 #3686"), - (drop_unchained_merkle_shreds::id(), "drops unchained Merkle shreds #2149"), - (relax_intrabatch_account_locks::id(), "Allow batched transactions to read/write and write/write the same accounts SIMD-0083"), - (create_slashing_program::id(), "creates an enshrined slashing program SIMD-0204"), - (disable_partitioned_rent_collection::id(), "Disable partitioned rent collection SIMD-0175 #4562"), - (enable_vote_address_leader_schedule::id(), "Enable vote address leader schedule SIMD-0180 #4573"), - /*************** ADD NEW FEATURES HERE ***************/ - ] - .iter() - .cloned() - .collect(); - - /// Unique identifier of the current software's feature set - pub static ref ID: Hash = { - let mut hasher = Hasher::default(); - let mut feature_ids = FEATURE_NAMES.keys().collect::>(); - feature_ids.sort(); - for feature in feature_ids { - hasher.hash(feature.as_ref()); - } - hasher.result() - }; -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct FullInflationFeaturePair { - pub vote_id: Pubkey, // Feature that grants the candidate the ability to enable full inflation - pub enable_id: Pubkey, // Feature to enable full inflation by the candidate -} - -lazy_static! { - /// Set of feature pairs that once enabled will trigger full inflation - pub static ref FULL_INFLATION_FEATURE_PAIRS: AHashSet = [ - FullInflationFeaturePair { - vote_id: full_inflation::mainnet::certusone::vote::id(), - enable_id: full_inflation::mainnet::certusone::enable::id(), - }, - ] - .iter() - .cloned() - .collect(); -} - -/// `FeatureSet` holds the set of currently active/inactive runtime features -#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct FeatureSet { - pub active: AHashMap, - pub inactive: AHashSet, -} -impl Default for FeatureSet { - fn default() -> Self { - // All features disabled - Self { - active: AHashMap::new(), - inactive: FEATURE_NAMES.keys().cloned().collect(), - } - } -} -impl FeatureSet { - pub fn is_active(&self, feature_id: &Pubkey) -> bool { - self.active.contains_key(feature_id) - } - - pub fn activated_slot(&self, feature_id: &Pubkey) -> Option { - self.active.get(feature_id).copied() - } - - /// List of enabled features that trigger full inflation - pub fn full_inflation_features_enabled(&self) -> AHashSet { - let mut hash_set = FULL_INFLATION_FEATURE_PAIRS - .iter() - .filter_map(|pair| { - if self.is_active(&pair.vote_id) && self.is_active(&pair.enable_id) { - Some(pair.enable_id) - } else { - None - } - }) - .collect::>(); - - if self.is_active(&full_inflation::devnet_and_testnet::id()) { - hash_set.insert(full_inflation::devnet_and_testnet::id()); - } - hash_set - } - - /// All features enabled, useful for testing - pub fn all_enabled() -> Self { - Self { - active: FEATURE_NAMES.keys().cloned().map(|key| (key, 0)).collect(), - inactive: AHashSet::new(), - } - } - - /// Activate a feature - pub fn activate(&mut self, feature_id: &Pubkey, slot: u64) { - self.inactive.remove(feature_id); - self.active.insert(*feature_id, slot); - } - - /// Deactivate a feature - pub fn deactivate(&mut self, feature_id: &Pubkey) { - self.active.remove(feature_id); - self.inactive.insert(*feature_id); - } - - pub fn new_warmup_cooldown_rate_epoch(&self, epoch_schedule: &EpochSchedule) -> Option { - self.activated_slot(&reduce_stake_warmup_cooldown::id()) - .map(|slot| epoch_schedule.get_epoch(slot)) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_full_inflation_features_enabled_devnet_and_testnet() { - let mut feature_set = FeatureSet::default(); - assert!(feature_set.full_inflation_features_enabled().is_empty()); - feature_set - .active - .insert(full_inflation::devnet_and_testnet::id(), 42); - assert_eq!( - feature_set.full_inflation_features_enabled(), - [full_inflation::devnet_and_testnet::id()] - .iter() - .cloned() - .collect() - ); - } - - #[test] - fn test_full_inflation_features_enabled() { - // Normal sequence: vote_id then enable_id - let mut feature_set = FeatureSet::default(); - assert!(feature_set.full_inflation_features_enabled().is_empty()); - feature_set - .active - .insert(full_inflation::mainnet::certusone::vote::id(), 42); - assert!(feature_set.full_inflation_features_enabled().is_empty()); - feature_set - .active - .insert(full_inflation::mainnet::certusone::enable::id(), 42); - assert_eq!( - feature_set.full_inflation_features_enabled(), - [full_inflation::mainnet::certusone::enable::id()] - .iter() - .cloned() - .collect() - ); - - // Backwards sequence: enable_id and then vote_id - let mut feature_set = FeatureSet::default(); - assert!(feature_set.full_inflation_features_enabled().is_empty()); - feature_set - .active - .insert(full_inflation::mainnet::certusone::enable::id(), 42); - assert!(feature_set.full_inflation_features_enabled().is_empty()); - feature_set - .active - .insert(full_inflation::mainnet::certusone::vote::id(), 42); - assert_eq!( - feature_set.full_inflation_features_enabled(), - [full_inflation::mainnet::certusone::enable::id()] - .iter() - .cloned() - .collect() - ); - } - - #[test] - fn test_feature_set_activate_deactivate() { - let mut feature_set = FeatureSet::default(); - - let feature = Pubkey::new_unique(); - assert!(!feature_set.is_active(&feature)); - feature_set.activate(&feature, 0); - assert!(feature_set.is_active(&feature)); - feature_set.deactivate(&feature); - assert!(!feature_set.is_active(&feature)); - } -} diff --git a/fee-structure/Cargo.toml b/fee-structure/Cargo.toml index 40b943617..8a7c7b358 100644 --- a/fee-structure/Cargo.toml +++ b/fee-structure/Cargo.toml @@ -24,10 +24,6 @@ serde_derive = { workspace = true, optional = true } solana-frozen-abi = { workspace = true, optional = true, features = [ "frozen-abi", ] } -solana-native-token = { workspace = true } - -[target.'cfg(not(target_os = "solana"))'.dependencies] -solana-message = { workspace = true } [lints] workspace = true diff --git a/fee-structure/src/lib.rs b/fee-structure/src/lib.rs index 5f458c14d..58bc77f5f 100644 --- a/fee-structure/src/lib.rs +++ b/fee-structure/src/lib.rs @@ -2,8 +2,6 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(feature = "frozen-abi", feature(min_specialization))] -#[cfg(not(target_os = "solana"))] -use solana_message::SanitizedMessage; use std::num::NonZeroU32; /// A fee and its associated compute unit limit @@ -76,30 +74,6 @@ impl FeeDetails { pub const ACCOUNT_DATA_COST_PAGE_SIZE: u64 = 32_u64.saturating_mul(1024); impl FeeStructure { - #[deprecated( - since = "2.3.0", - note = "Use FeeStructure::default() and modify fields as needed" - )] - #[allow(deprecated)] - pub fn new( - sol_per_signature: f64, - sol_per_write_lock: f64, - compute_fee_bins: Vec<(u64, f64)>, - ) -> Self { - let compute_fee_bins = compute_fee_bins - .iter() - .map(|(limit, sol)| FeeBin { - limit: *limit, - fee: solana_native_token::sol_to_lamports(*sol), - }) - .collect::>(); - FeeStructure { - lamports_per_signature: solana_native_token::sol_to_lamports(sol_per_signature), - lamports_per_write_lock: solana_native_token::sol_to_lamports(sol_per_write_lock), - compute_fee_bins, - } - } - pub fn get_max_fee(&self, num_signatures: u64, num_write_locks: u64) -> u64 { num_signatures .saturating_mul(self.lamports_per_signature) @@ -121,87 +95,6 @@ impl FeeStructure { .saturating_div(ACCOUNT_DATA_COST_PAGE_SIZE) .saturating_mul(heap_cost) } - - /// Calculate fee for `SanitizedMessage` - #[cfg(not(target_os = "solana"))] - #[deprecated( - since = "2.1.0", - note = "Please use `solana_fee::calculate_fee` instead." - )] - pub fn calculate_fee( - &self, - message: &SanitizedMessage, - lamports_per_signature: u64, - budget_limits: &FeeBudgetLimits, - include_loaded_account_data_size_in_fee: bool, - ) -> u64 { - #[allow(deprecated)] - self.calculate_fee_details( - message, - lamports_per_signature, - budget_limits, - include_loaded_account_data_size_in_fee, - ) - .total_fee() - } - - /// Calculate fee details for `SanitizedMessage` - #[cfg(not(target_os = "solana"))] - #[deprecated( - since = "2.1.0", - note = "Please use `solana_fee::calculate_fee_details` instead." - )] - pub fn calculate_fee_details( - &self, - message: &SanitizedMessage, - lamports_per_signature: u64, - budget_limits: &FeeBudgetLimits, - include_loaded_account_data_size_in_fee: bool, - ) -> FeeDetails { - // Backward compatibility - lamports_per_signature == 0 means to clear - // transaction fee to zero - if lamports_per_signature == 0 { - return FeeDetails::default(); - } - - let signature_fee = message - .num_total_signatures() - .saturating_mul(self.lamports_per_signature); - let write_lock_fee = message - .num_write_locks() - .saturating_mul(self.lamports_per_write_lock); - - // `compute_fee` covers costs for both requested_compute_units and - // requested_loaded_account_data_size - let loaded_accounts_data_size_cost = if include_loaded_account_data_size_in_fee { - FeeStructure::calculate_memory_usage_cost( - budget_limits.loaded_accounts_data_size_limit.get(), - budget_limits.heap_cost, - ) - } else { - 0_u64 - }; - let total_compute_units = - loaded_accounts_data_size_cost.saturating_add(budget_limits.compute_unit_limit); - let compute_fee = self - .compute_fee_bins - .iter() - .find(|bin| total_compute_units <= bin.limit) - .map(|bin| bin.fee) - .unwrap_or_else(|| { - self.compute_fee_bins - .last() - .map(|bin| bin.fee) - .unwrap_or_default() - }); - - FeeDetails { - transaction_fee: signature_fee - .saturating_add(write_lock_fee) - .saturating_add(compute_fee), - prioritization_fee: budget_limits.prioritization_fee, - } - } } impl Default for FeeStructure { diff --git a/file-download/Cargo.toml b/file-download/Cargo.toml index 112200964..c9fc01027 100644 --- a/file-download/Cargo.toml +++ b/file-download/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-file-download" description = "Solana File Download Utility" documentation = "https://docs.rs/solana-file-download" -version = "2.2.2" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/frozen-abi-macro/Cargo.toml b/frozen-abi-macro/Cargo.toml index fcb6ff2db..b7a8b002f 100644 --- a/frozen-abi-macro/Cargo.toml +++ b/frozen-abi-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-frozen-abi-macro" description = "Solana Frozen ABI Macro" documentation = "https://docs.rs/solana-frozen-abi-macro" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/frozen-abi/Cargo.toml b/frozen-abi/Cargo.toml index 72efbc459..9f0a81026 100644 --- a/frozen-abi/Cargo.toml +++ b/frozen-abi/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-frozen-abi" description = "Solana Frozen ABI" documentation = "https://docs.rs/solana-frozen-abi" -version = "2.2.2" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -16,9 +16,11 @@ default = [] frozen-abi = [] [dependencies] +boxcar = { workspace = true } bs58 = { workspace = true, features = ["alloc"] } bv = { workspace = true, features = ["serde"] } bytes = { workspace = true } +dashmap = { workspace = true } log = { workspace = true, features = ["std"] } serde = { workspace = true, features = ["rc"] } serde_derive = { workspace = true } diff --git a/frozen-abi/src/abi_example.rs b/frozen-abi/src/abi_example.rs index c844b3a11..980bb1d01 100644 --- a/frozen-abi/src/abi_example.rs +++ b/frozen-abi/src/abi_example.rs @@ -19,7 +19,7 @@ use { // // The requirement of AbiExample impls even applies to those types of `#[serde(skip)]`-ed fields. // That's because the abi digesting needs a properly initialized object to enter into the -// serde::serialize() to begin with, even knowning they aren't used for serialization and thus abi +// serde::serialize() to begin with, even knowing they aren't used for serialization and thus abi // digest. Luckily, `#[serde(skip)]`-ed fields' AbiExample impls can just delegate to T::default(), // exploiting the nature of this artificial impl requirement as an exception from the usual // AbiExample semantics. @@ -619,3 +619,28 @@ impl AbiExample for std::sync::OnceLock { Self::from(T::example()) } } + +#[cfg(not(target_os = "solana"))] +impl< + T: std::cmp::Eq + std::hash::Hash + AbiExample, + S: AbiExample, + H: std::hash::BuildHasher + Default + std::clone::Clone, + > AbiExample for dashmap::DashMap +{ + fn example() -> Self { + info!("AbiExample for (DashMap): {}", type_name::()); + let map = dashmap::DashMap::default(); + map.insert(T::example(), S::example()); + map + } +} + +#[cfg(not(target_os = "solana"))] +impl AbiExample for boxcar::Vec { + fn example() -> Self { + info!("AbiExample for (boxcar::Vec): {}", type_name::()); + let vec = boxcar::Vec::new(); + vec.push(T::example()); + vec + } +} diff --git a/genesis-config/Cargo.toml b/genesis-config/Cargo.toml index bedf50875..3f2126b42 100644 --- a/genesis-config/Cargo.toml +++ b/genesis-config/Cargo.toml @@ -15,7 +15,11 @@ all-features = true rustdoc-args = ["--cfg=docsrs"] [features] -frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"] +frozen-abi = [ + "dep:solana-frozen-abi", + "dep:solana-frozen-abi-macro", + "dep:solana-logger", +] serde = [ "dep:serde", "dep:serde_derive", @@ -45,7 +49,7 @@ solana-frozen-abi-macro = { workspace = true, optional = true } solana-hash = { workspace = true } solana-inflation = { workspace = true } solana-keypair = { workspace = true } -solana-logger = { workspace = true } +solana-logger = { workspace = true, optional = true } solana-poh-config = { workspace = true } solana-pubkey = { workspace = true } solana-rent = { workspace = true } diff --git a/genesis-config/src/lib.rs b/genesis-config/src/lib.rs index 4ba1cf46a..bc181f93f 100644 --- a/genesis-config/src/lib.rs +++ b/genesis-config/src/lib.rs @@ -2,11 +2,6 @@ #![cfg_attr(feature = "frozen-abi", feature(min_specialization))] #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#[deprecated( - since = "2.2.0", - note = "Use `solana_cluster_type::ClusterType` instead." -)] -pub use solana_cluster_type::ClusterType; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; #[cfg(feature = "serde")] @@ -27,6 +22,7 @@ use { use { solana_account::{Account, AccountSharedData}, solana_clock::{UnixTimestamp, DEFAULT_TICKS_PER_SLOT}, + solana_cluster_type::ClusterType, solana_epoch_schedule::EpochSchedule, solana_fee_calculator::FeeRateGovernor, solana_inflation::Inflation, @@ -53,7 +49,7 @@ pub const UNUSED_DEFAULT: u64 = 1024; #[cfg_attr( feature = "frozen-abi", derive(AbiExample), - frozen_abi(digest = "D9VFRSj4fodCuKFC9omQY2zY2Uw8wo6SzJFLeMJaVigm") + frozen_abi(digest = "3tUUJkZiUUGfuNCXbDuDR6KCQYPsh3m3cPw5vVUSt113") )] #[cfg_attr( feature = "serde", diff --git a/hard-forks/src/lib.rs b/hard-forks/src/lib.rs index fc2cfdb0a..d97a78c5a 100644 --- a/hard-forks/src/lib.rs +++ b/hard-forks/src/lib.rs @@ -29,7 +29,7 @@ impl HardForks { } // Returns a sorted-by-slot iterator over the registered hark forks - pub fn iter(&self) -> std::slice::Iter<(u64, usize)> { + pub fn iter(&self) -> std::slice::Iter<'_, (u64, usize)> { self.hard_forks.iter() } diff --git a/hash/Cargo.toml b/hash/Cargo.toml index 127764685..43a020c54 100644 --- a/hash/Cargo.toml +++ b/hash/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-hash" description = "Solana wrapper for the 32-byte output of a hashing algorithm." documentation = "https://docs.rs/solana-hash" version = "2.3.0" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -38,10 +39,6 @@ solana-frozen-abi-macro = { workspace = true, optional = true, features = [ ] } solana-sanitize = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -js-sys = { workspace = true } -wasm-bindgen = { workspace = true } - [dev-dependencies] bs58 = { workspace = true, default-features = false, features = ["alloc"] } diff --git a/hash/src/lib.rs b/hash/src/lib.rs index bd0af69ba..392f82861 100644 --- a/hash/src/lib.rs +++ b/hash/src/lib.rs @@ -3,28 +3,21 @@ #![cfg_attr(feature = "frozen-abi", feature(min_specialization))] #[cfg(feature = "borsh")] use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -#[cfg(any(feature = "std", target_arch = "wasm32"))] +#[cfg(feature = "std")] extern crate std; #[cfg(feature = "bytemuck")] use bytemuck_derive::{Pod, Zeroable}; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; -#[cfg(any(all(feature = "borsh", feature = "std"), target_arch = "wasm32"))] +#[cfg(all(feature = "borsh", feature = "std"))] use std::string::ToString; use { core::{ - convert::TryFrom, fmt, str::{from_utf8_unchecked, FromStr}, }, solana_sanitize::Sanitize, }; -#[cfg(target_arch = "wasm32")] -use { - js_sys::{Array, Uint8Array}, - std::{boxed::Box, format, string::String, vec}, - wasm_bindgen::{prelude::*, JsCast}, -}; /// Size of a hash in bytes. pub const HASH_BYTES: usize = 32; @@ -38,7 +31,6 @@ pub const MAX_BASE58_LEN: usize = 44; /// /// [SHA-256]: https://en.wikipedia.org/wiki/SHA-2 /// [blake3]: https://github.com/BLAKE3-team/BLAKE3 -#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] #[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] #[cfg_attr( feature = "borsh", @@ -92,8 +84,7 @@ pub enum ParseHashError { Invalid, } -#[cfg(feature = "std")] -impl std::error::Error for ParseHashError {} +impl core::error::Error for ParseHashError {} impl fmt::Display for ParseHashError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -125,11 +116,6 @@ impl FromStr for Hash { } impl Hash { - #[deprecated(since = "2.2.0", note = "Use 'Hash::new_from_array' instead")] - pub fn new(hash_slice: &[u8]) -> Self { - Hash(<[u8; HASH_BYTES]>::try_from(hash_slice).unwrap()) - } - pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self { Self(hash_array) } @@ -145,65 +131,12 @@ impl Hash { Self::new_from_array(b) } - pub fn to_bytes(self) -> [u8; HASH_BYTES] { + pub const fn to_bytes(self) -> [u8; HASH_BYTES] { self.0 } -} - -#[cfg(target_arch = "wasm32")] -#[allow(non_snake_case)] -#[wasm_bindgen] -impl Hash { - /// Create a new Hash object - /// - /// * `value` - optional hash as a base58 encoded string, `Uint8Array`, `[number]` - #[wasm_bindgen(constructor)] - pub fn constructor(value: JsValue) -> Result { - if let Some(base58_str) = value.as_string() { - base58_str - .parse::() - .map_err(|x| JsValue::from(x.to_string())) - } else if let Some(uint8_array) = value.dyn_ref::() { - <[u8; HASH_BYTES]>::try_from(uint8_array.to_vec()) - .map(Hash::new_from_array) - .map_err(|err| format!("Invalid Hash value: {err:?}").into()) - } else if let Some(array) = value.dyn_ref::() { - let mut bytes = vec![]; - let iterator = js_sys::try_iter(&array.values())?.expect("array to be iterable"); - for x in iterator { - let x = x?; - - if let Some(n) = x.as_f64() { - if n >= 0. && n <= 255. { - bytes.push(n as u8); - continue; - } - } - return Err(format!("Invalid array argument: {:?}", x).into()); - } - <[u8; HASH_BYTES]>::try_from(bytes) - .map(Hash::new_from_array) - .map_err(|err| format!("Invalid Hash value: {err:?}").into()) - } else if value.is_undefined() { - Ok(Hash::default()) - } else { - Err("Unsupported argument".into()) - } - } - - /// Return the base58 string representation of the hash - pub fn toString(&self) -> String { - self.to_string() - } - - /// Checks if two `Hash`s are equal - pub fn equals(&self, other: &Hash) -> bool { - self == other - } - /// Return the `Uint8Array` representation of the hash - pub fn toBytes(&self) -> Box<[u8]> { - self.0.clone().into() + pub const fn as_bytes(&self) -> &[u8; HASH_BYTES] { + &self.0 } } diff --git a/instruction-error/Cargo.toml b/instruction-error/Cargo.toml new file mode 100644 index 000000000..3b38e5f73 --- /dev/null +++ b/instruction-error/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "solana-instruction-error" +description = "Solana InstructionError type." +documentation = "https://docs.rs/solana-instruction-error" +version = "1.0.0" +rust-version = "1.81.0" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +all-features = true +rustdoc-args = ["--cfg=docsrs"] + +[features] +frozen-abi = [ + "dep:solana-frozen-abi", + "dep:solana-frozen-abi-macro", + "serde", +] +num-traits = ["dep:num-traits"] +serde = ["dep:serde", "dep:serde_derive"] + +[dependencies] +num-traits = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +solana-frozen-abi = { workspace = true, optional = true } +solana-frozen-abi-macro = { workspace = true, optional = true } +solana-program-error = { workspace = true } + +[lints] +workspace = true diff --git a/instruction/src/error.rs b/instruction-error/src/lib.rs similarity index 81% rename from instruction/src/error.rs rename to instruction-error/src/lib.rs index ea213cd85..b82e9c337 100644 --- a/instruction/src/error.rs +++ b/instruction-error/src/lib.rs @@ -1,51 +1,22 @@ -use core::fmt; +#![no_std] +#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] +#[cfg(feature = "num-traits")] +use num_traits::ToPrimitive; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{AbiEnumVisitor, AbiExample}; -#[cfg(feature = "std")] -use { - num_traits::ToPrimitive, - std::string::{String, ToString}, +#[cfg(feature = "frozen-abi")] +extern crate std; +pub use solana_program_error::{ + ACCOUNT_ALREADY_INITIALIZED, ACCOUNT_BORROW_FAILED, ACCOUNT_DATA_TOO_SMALL, + ACCOUNT_NOT_RENT_EXEMPT, ARITHMETIC_OVERFLOW, BORSH_IO_ERROR, + BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS, CUSTOM_ZERO, ILLEGAL_OWNER, IMMUTABLE, + INCORRECT_AUTHORITY, INCORRECT_PROGRAM_ID, INSUFFICIENT_FUNDS, INVALID_ACCOUNT_DATA, + INVALID_ACCOUNT_DATA_REALLOC, INVALID_ACCOUNT_OWNER, INVALID_ARGUMENT, + INVALID_INSTRUCTION_DATA, INVALID_SEEDS, MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED, + MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED, MAX_SEED_LENGTH_EXCEEDED, MISSING_REQUIRED_SIGNATURES, + NOT_ENOUGH_ACCOUNT_KEYS, UNINITIALIZED_ACCOUNT, UNSUPPORTED_SYSVAR, }; - -/// Builtin return values occupy the upper 32 bits -const BUILTIN_BIT_SHIFT: usize = 32; -macro_rules! to_builtin { - ($error:expr) => { - ($error as u64) << BUILTIN_BIT_SHIFT - }; -} - -pub const CUSTOM_ZERO: u64 = to_builtin!(1); -pub const INVALID_ARGUMENT: u64 = to_builtin!(2); -pub const INVALID_INSTRUCTION_DATA: u64 = to_builtin!(3); -pub const INVALID_ACCOUNT_DATA: u64 = to_builtin!(4); -pub const ACCOUNT_DATA_TOO_SMALL: u64 = to_builtin!(5); -pub const INSUFFICIENT_FUNDS: u64 = to_builtin!(6); -pub const INCORRECT_PROGRAM_ID: u64 = to_builtin!(7); -pub const MISSING_REQUIRED_SIGNATURES: u64 = to_builtin!(8); -pub const ACCOUNT_ALREADY_INITIALIZED: u64 = to_builtin!(9); -pub const UNINITIALIZED_ACCOUNT: u64 = to_builtin!(10); -pub const NOT_ENOUGH_ACCOUNT_KEYS: u64 = to_builtin!(11); -pub const ACCOUNT_BORROW_FAILED: u64 = to_builtin!(12); -pub const MAX_SEED_LENGTH_EXCEEDED: u64 = to_builtin!(13); -pub const INVALID_SEEDS: u64 = to_builtin!(14); -pub const BORSH_IO_ERROR: u64 = to_builtin!(15); -pub const ACCOUNT_NOT_RENT_EXEMPT: u64 = to_builtin!(16); -pub const UNSUPPORTED_SYSVAR: u64 = to_builtin!(17); -pub const ILLEGAL_OWNER: u64 = to_builtin!(18); -pub const MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED: u64 = to_builtin!(19); -pub const INVALID_ACCOUNT_DATA_REALLOC: u64 = to_builtin!(20); -pub const MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED: u64 = to_builtin!(21); -pub const BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS: u64 = to_builtin!(22); -pub const INVALID_ACCOUNT_OWNER: u64 = to_builtin!(23); -pub const ARITHMETIC_OVERFLOW: u64 = to_builtin!(24); -pub const IMMUTABLE: u64 = to_builtin!(25); -pub const INCORRECT_AUTHORITY: u64 = to_builtin!(26); -// Warning: Any new error codes added here must also be: -// - Added to the below conversions -// - Added as an equivalent to ProgramError and InstructionError -// - Be featurized in the BPF loader to return `InstructionError::InvalidError` -// until the feature is activated +use {core::fmt, solana_program_error::ProgramError}; /// Reasons the runtime might have rejected an instruction. /// @@ -54,7 +25,6 @@ pub const INCORRECT_AUTHORITY: u64 = to_builtin!(26); /// an error be consistent across software versions. For example, it is /// dangerous to include error strings from 3rd party crates because they could /// change at any time and changes to them are difficult to detect. -#[cfg(feature = "std")] #[cfg_attr(feature = "frozen-abi", derive(AbiExample, AbiEnumVisitor))] #[cfg_attr( feature = "serde", @@ -202,15 +172,7 @@ pub enum InstructionError { IncorrectAuthority, /// Failed to serialize or deserialize account data - /// - /// Warning: This error should never be emitted by the runtime. - /// - /// This error includes strings from the underlying 3rd party Borsh crate - /// which can be dangerous because the error strings could change across - /// Borsh versions. Only programs can use this error because they are - /// consistent across Solana software versions. - /// - BorshIoError(String), + BorshIoError, /// An account does not have enough lamports to be rent-exempt AccountNotRentExempt, @@ -242,10 +204,8 @@ pub enum InstructionError { // conversions must also be added } -#[cfg(feature = "std")] -impl std::error::Error for InstructionError {} +impl core::error::Error for InstructionError {} -#[cfg(feature = "std")] impl fmt::Display for InstructionError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -361,8 +321,8 @@ impl fmt::Display for InstructionError { InstructionError::ProgramFailedToCompile => f.write_str("Program failed to compile"), InstructionError::Immutable => f.write_str("Account is immutable"), InstructionError::IncorrectAuthority => f.write_str("Incorrect authority provided"), - InstructionError::BorshIoError(s) => { - write!(f, "Failed to serialize or deserialize account data: {s}",) + InstructionError::BorshIoError => { + f.write_str("Failed to serialize or deserialize account data") } InstructionError::AccountNotRentExempt => { f.write_str("An account does not have enough lamports to be rent-exempt") @@ -385,7 +345,7 @@ impl fmt::Display for InstructionError { } } -#[cfg(feature = "std")] +#[cfg(feature = "num-traits")] impl From for InstructionError where T: ToPrimitive, @@ -407,7 +367,7 @@ where ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed, MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded, INVALID_SEEDS => Self::InvalidSeeds, - BORSH_IO_ERROR => Self::BorshIoError("Unknown".to_string()), + BORSH_IO_ERROR => Self::BorshIoError, ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt, UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar, ILLEGAL_OWNER => Self::IllegalOwner, @@ -423,7 +383,7 @@ where INCORRECT_AUTHORITY => Self::IncorrectAuthority, _ => { // A valid custom error has no bits set in the upper 32 - if error >> BUILTIN_BIT_SHIFT == 0 { + if error >> solana_program_error::BUILTIN_BIT_SHIFT == 0 { Self::Custom(error as u32) } else { Self::InvalidError @@ -441,8 +401,7 @@ pub enum LamportsError { ArithmeticOverflow, } -#[cfg(feature = "std")] -impl std::error::Error for LamportsError {} +impl core::error::Error for LamportsError {} impl fmt::Display for LamportsError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -453,7 +412,6 @@ impl fmt::Display for LamportsError { } } -#[cfg(feature = "std")] impl From for InstructionError { fn from(error: LamportsError) -> Self { match error { @@ -462,3 +420,45 @@ impl From for InstructionError { } } } + +impl TryFrom for ProgramError { + type Error = InstructionError; + + fn try_from(error: InstructionError) -> Result { + match error { + Self::Error::Custom(err) => Ok(Self::Custom(err)), + Self::Error::InvalidArgument => Ok(Self::InvalidArgument), + Self::Error::InvalidInstructionData => Ok(Self::InvalidInstructionData), + Self::Error::InvalidAccountData => Ok(Self::InvalidAccountData), + Self::Error::AccountDataTooSmall => Ok(Self::AccountDataTooSmall), + Self::Error::InsufficientFunds => Ok(Self::InsufficientFunds), + Self::Error::IncorrectProgramId => Ok(Self::IncorrectProgramId), + Self::Error::MissingRequiredSignature => Ok(Self::MissingRequiredSignature), + Self::Error::AccountAlreadyInitialized => Ok(Self::AccountAlreadyInitialized), + Self::Error::UninitializedAccount => Ok(Self::UninitializedAccount), + Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys), + Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed), + Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded), + Self::Error::InvalidSeeds => Ok(Self::InvalidSeeds), + Self::Error::BorshIoError => Ok(Self::BorshIoError), + Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt), + Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar), + Self::Error::IllegalOwner => Ok(Self::IllegalOwner), + Self::Error::MaxAccountsDataAllocationsExceeded => { + Ok(Self::MaxAccountsDataAllocationsExceeded) + } + Self::Error::InvalidRealloc => Ok(Self::InvalidRealloc), + Self::Error::MaxInstructionTraceLengthExceeded => { + Ok(Self::MaxInstructionTraceLengthExceeded) + } + Self::Error::BuiltinProgramsMustConsumeComputeUnits => { + Ok(Self::BuiltinProgramsMustConsumeComputeUnits) + } + Self::Error::InvalidAccountOwner => Ok(Self::InvalidAccountOwner), + Self::Error::ArithmeticOverflow => Ok(Self::ArithmeticOverflow), + Self::Error::Immutable => Ok(Self::Immutable), + Self::Error::IncorrectAuthority => Ok(Self::IncorrectAuthority), + _ => Err(error), + } + } +} diff --git a/instruction/Cargo.toml b/instruction/Cargo.toml index 199f03fed..c9660d92d 100644 --- a/instruction/Cargo.toml +++ b/instruction/Cargo.toml @@ -10,7 +10,7 @@ license = { workspace = true } edition = { workspace = true } [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +targets = ["x86_64-unknown-linux-gnu"] all-features = true rustdoc-args = ["--cfg=docsrs"] @@ -31,18 +31,13 @@ syscalls = ["std"] [dependencies] bincode = { workspace = true, optional = true } borsh = { workspace = true, optional = true } -num-traits = { workspace = true } serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } solana-frozen-abi = { workspace = true, optional = true } solana-frozen-abi-macro = { workspace = true, optional = true } +solana-instruction-error = { workspace = true, features = ["num-traits"] } solana-pubkey = { workspace = true, default-features = false } -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { workspace = true, features = ["js", "wasm-bindgen"] } -js-sys = { workspace = true } -wasm-bindgen = { workspace = true } - [target.'cfg(target_os = "solana")'.dependencies] solana-define-syscall = { workspace = true } diff --git a/instruction/src/lib.rs b/instruction/src/lib.rs index 899cf9d2a..1d2801c4e 100644 --- a/instruction/src/lib.rs +++ b/instruction/src/lib.rs @@ -11,7 +11,6 @@ //! [`AccountMeta`] values. The runtime uses this information to efficiently //! schedule execution of transactions. #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] #![allow(clippy::arithmetic_side_effects)] #![no_std] @@ -23,11 +22,9 @@ use std::vec::Vec; pub mod account_meta; #[cfg(feature = "std")] pub use account_meta::AccountMeta; -pub mod error; +pub use solana_instruction_error as error; #[cfg(any(feature = "syscalls", target_os = "solana"))] pub mod syscalls; -#[cfg(all(feature = "std", target_arch = "wasm32"))] -pub mod wasm; /// A directive for a single invocation of a Solana program. /// @@ -88,7 +85,7 @@ pub mod wasm; /// Programs may require signatures from some accounts, in which case they /// should be specified as signers during `Instruction` construction. The /// program must still validate during execution that the account is a signer. -#[cfg(all(feature = "std", not(target_arch = "wasm32")))] +#[cfg(feature = "std")] #[cfg_attr( feature = "serde", derive(serde_derive::Serialize, serde_derive::Deserialize) @@ -103,25 +100,6 @@ pub struct Instruction { pub data: Vec, } -/// wasm-bindgen version of the Instruction struct. -/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671 -/// is fixed. This must not diverge from the regular non-wasm Instruction struct. -#[cfg(all(feature = "std", target_arch = "wasm32"))] -#[wasm_bindgen::prelude::wasm_bindgen] -#[cfg_attr( - feature = "serde", - derive(serde_derive::Serialize, serde_derive::Deserialize) -)] -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Instruction { - #[wasm_bindgen(skip)] - pub program_id: Pubkey, - #[wasm_bindgen(skip)] - pub accounts: Vec, - #[wasm_bindgen(skip)] - pub data: Vec, -} - #[cfg(feature = "std")] impl Instruction { #[cfg(feature = "borsh")] diff --git a/instruction/src/syscalls.rs b/instruction/src/syscalls.rs index 2fd3bc0d5..11e5b27e0 100644 --- a/instruction/src/syscalls.rs +++ b/instruction/src/syscalls.rs @@ -69,9 +69,9 @@ pub fn get_processed_sibling_instruction(index: usize) -> Option { /// Get the current stack height. /// -/// Transaction-level instructions are height [`TRANSACTION_LEVEL_STACK_HEIGHT`]`, -/// fist invoked inner instruction is height `TRANSACTION_LEVEL_STACK_HEIGHT + 1`, -/// and so forth. +/// Transaction-level instructions are height +/// [`crate::TRANSACTION_LEVEL_STACK_HEIGHT`]`, fist invoked inner instruction +/// is height `TRANSACTION_LEVEL_STACK_HEIGHT + 1`, and so forth. #[cfg(feature = "syscalls")] pub fn get_stack_height() -> usize { #[cfg(target_os = "solana")] diff --git a/instruction/src/wasm.rs b/instruction/src/wasm.rs deleted file mode 100644 index 03c88bb75..000000000 --- a/instruction/src/wasm.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! The `Instructions` struct is a legacy workaround -//! from when wasm-bindgen lacked Vec support -//! (ref: https://github.com/rustwasm/wasm-bindgen/issues/111) -use {crate::Instruction, wasm_bindgen::prelude::*}; - -#[wasm_bindgen] -#[derive(Default)] -pub struct Instructions { - instructions: std::vec::Vec, -} - -#[wasm_bindgen] -impl Instructions { - #[wasm_bindgen(constructor)] - pub fn constructor() -> Instructions { - Instructions::default() - } - - pub fn push(&mut self, instruction: Instruction) { - self.instructions.push(instruction); - } -} - -impl From for std::vec::Vec { - fn from(instructions: Instructions) -> Self { - instructions.instructions - } -} diff --git a/instructions-sysvar/Cargo.toml b/instructions-sysvar/Cargo.toml index 4516436d5..2cee4309f 100644 --- a/instructions-sysvar/Cargo.toml +++ b/instructions-sysvar/Cargo.toml @@ -20,7 +20,8 @@ dev-context-only-utils = ["dep:qualifier_attr"] [dependencies] qualifier_attr = { workspace = true, optional = true } solana-account-info = { workspace = true } -solana-instruction = { workspace = true, default-features = false } +solana-instruction = { workspace = true, default-features = false, features = ["std"] } +solana-instruction-error = { workspace = true } solana-program-error = { workspace = true } solana-pubkey = { workspace = true, default-features = false } solana-sanitize = { workspace = true } diff --git a/instructions-sysvar/src/lib.rs b/instructions-sysvar/src/lib.rs index 17e6c877d..288433d16 100644 --- a/instructions-sysvar/src/lib.rs +++ b/instructions-sysvar/src/lib.rs @@ -14,7 +14,7 @@ //! instruction sysvar is accessed through several free functions within this //! module. //! -//! [`Sysvar`]: crate::Sysvar +//! [`Sysvar`]: https://docs.rs/solana-sysvar/latest/solana_sysvar/trait.Sysvar.html //! //! See also the Solana [documentation on the instructions sysvar][sdoc]. //! @@ -41,7 +41,8 @@ use { }; use { solana_account_info::AccountInfo, - solana_instruction::{error::InstructionError, AccountMeta, Instruction}, + solana_instruction::{AccountMeta, Instruction}, + solana_instruction_error::InstructionError, solana_program_error::ProgramError, solana_sanitize::SanitizeError, solana_serialize_utils::{read_pubkey, read_slice, read_u16, read_u8}, @@ -54,7 +55,7 @@ use { /// but does not implement the [`Sysvar`] trait. /// /// [`SysvarId`]: https://docs.rs/solana-sysvar-id/latest/solana_sysvar_id/trait.SysvarId.html -/// [`Sysvar`]: crate::Sysvar +/// [`Sysvar`]: https://docs.rs/solana-sysvar/latest/solana_sysvar/trait.Sysvar.html /// /// Use the free functions in this module to access the instructions sysvar. pub struct Instructions(); @@ -81,19 +82,30 @@ bitflags! { } } -// First encode the number of instructions: -// [0..2 - num_instructions +// Instructions memory layout // -// Then a table of offsets of where to find them in the data -// 3..2 * num_instructions table of instruction offsets +// Header layout: +// [0..2] num_instructions (u16) +// [2..2 + 2*N] instruction_offsets ([u16; N]) // -// Each instruction is then encoded as: -// 0..2 - num_accounts -// 2 - meta_byte -> (bit 0 signer, bit 1 is_writable) -// 3..35 - pubkey - 32 bytes -// 35..67 - program_id -// 67..69 - data len - u16 -// 69..data_len - data +// Each instruction starts at an offset specified in `instruction_offsets`. +// The layout of each instruction is relative to its start offset. +// +// Instruction layout: +// [0..2] num_accounts (u16) +// [2..2 + 33*A] accounts ([AccountMeta; A]) +// [2 + 33*A..34 + 33*A] program_id (Pubkey) +// [34 + 33*A..36 + 33*A] data_len (u16) +// [36 + 33*A..36 + 33*A + D] data (&[u8]) +// +// AccountMeta layout: +// [0..1] meta (u8: bit 0: is_signer, bit 1: is_writable) +// [1..33] pubkey (Pubkey) +// +// Where: +// - N = num_instructions +// - A = number of accounts in a particular instruction +// - D = data_len #[cfg(not(target_os = "solana"))] #[cfg_attr(feature = "dev-context-only-utils", qualifiers(pub))] fn serialize_instructions(instructions: &[BorrowedInstruction]) -> Vec { @@ -160,13 +172,6 @@ pub fn load_current_index_checked( Ok(index) } -/// Store the current `Instruction`'s index in the instructions sysvar data. -#[deprecated(since = "2.2.1", note = "Use store_current_index_checked instead")] -pub fn store_current_index(data: &mut [u8], instruction_index: u16) { - let last_index = data.len() - 2; - data[last_index..last_index + 2].copy_from_slice(&instruction_index.to_le_bytes()); -} - /// Store the current `Instruction`'s index in the instructions sysvar data. pub fn store_current_index_checked( data: &mut [u8], @@ -305,7 +310,6 @@ mod tests { let mut data = [4u8; 10]; let res = store_current_index_checked(&mut data, 3); assert!(res.is_ok()); - #[allow(deprecated)] let index = load_current_index(&data); assert_eq!(index, 3); assert_eq!([4u8; 8], data[0..8]); @@ -326,7 +330,7 @@ mod tests { is_writable: bool, } - fn make_borrowed_instruction(params: &MakeInstructionParams) -> BorrowedInstruction { + fn make_borrowed_instruction(params: &MakeInstructionParams) -> BorrowedInstruction<'_> { let MakeInstructionParams { program_id, account_key, @@ -388,16 +392,8 @@ mod tests { let mut lamports = 0; let mut data = construct_instructions_data(&[borrowed_instruction0, borrowed_instruction1]); let owner = solana_sdk_ids::sysvar::id(); - let mut account_info = AccountInfo::new( - &key, - false, - false, - &mut lamports, - &mut data, - &owner, - false, - 0, - ); + let mut account_info = + AccountInfo::new(&key, false, false, &mut lamports, &mut data, &owner, false); assert_eq!( instruction0, @@ -447,16 +443,8 @@ mod tests { let res = store_current_index_checked(&mut data, 1); assert!(res.is_ok()); let owner = solana_sdk_ids::sysvar::id(); - let mut account_info = AccountInfo::new( - &key, - false, - false, - &mut lamports, - &mut data, - &owner, - false, - 0, - ); + let mut account_info = + AccountInfo::new(&key, false, false, &mut lamports, &mut data, &owner, false); assert_eq!(1, load_current_index_checked(&account_info).unwrap()); { @@ -517,16 +505,8 @@ mod tests { let res = store_current_index_checked(&mut data, 1); assert!(res.is_ok()); let owner = solana_sdk_ids::sysvar::id(); - let mut account_info = AccountInfo::new( - &key, - false, - false, - &mut lamports, - &mut data, - &owner, - false, - 0, - ); + let mut account_info = + AccountInfo::new(&key, false, false, &mut lamports, &mut data, &owner, false); assert_eq!( Err(ProgramError::InvalidArgument), diff --git a/keccak-hasher/Cargo.toml b/keccak-hasher/Cargo.toml index 01faff511..7026d7a35 100644 --- a/keccak-hasher/Cargo.toml +++ b/keccak-hasher/Cargo.toml @@ -15,33 +15,15 @@ all-features = true rustdoc-args = ["--cfg=docsrs"] [features] -borsh = ["dep:borsh", "std"] -frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro", "std"] -serde = ["dep:serde", "dep:serde_derive"] sha3 = ["dep:sha3"] -std = ["solana-hash/std"] [dependencies] -borsh = { workspace = true, optional = true } -serde = { workspace = true, optional = true } -serde_derive = { workspace = true, optional = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-frozen-abi-macro = { workspace = true, optional = true, features = [ - "frozen-abi", -] } solana-hash = { workspace = true } -solana-sanitize = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] -sha3 = { workspace = true } +sha3 = { workspace = true, optional = true } [target.'cfg(target_os = "solana")'.dependencies] -# sha3 should be removed in the next breaking release, -# as there's no reason to use the crate instead of the syscall -# onchain -sha3 = { workspace = true, optional = true } solana-define-syscall = { workspace = true } [lints] diff --git a/keccak-hasher/src/lib.rs b/keccak-hasher/src/lib.rs index b0a18694c..fcc67ed70 100644 --- a/keccak-hasher/src/lib.rs +++ b/keccak-hasher/src/lib.rs @@ -2,50 +2,19 @@ //! //! [keccak]: https://keccak.team/keccak.html #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] #![no_std] -#[cfg(feature = "std")] -extern crate std; -#[cfg(any(feature = "sha3", not(target_os = "solana")))] +#[cfg(all(feature = "sha3", not(target_os = "solana")))] use sha3::{Digest, Keccak256}; -pub use solana_hash::{ParseHashError, HASH_BYTES, MAX_BASE58_LEN}; -#[cfg(feature = "borsh")] -use { - borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, - std::string::ToString, -}; -use { - core::{fmt, str::FromStr}, - solana_sanitize::Sanitize, -}; +pub use solana_hash::{Hash, ParseHashError, HASH_BYTES, MAX_BASE58_LEN}; -// TODO: replace this with `solana_hash::Hash` in the -// next breaking change. -// It's a breaking change because the field is public -// here and private in `solana_hash`, and making -// it public in `solana_hash` would break wasm-bindgen -#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] -#[cfg_attr( - feature = "borsh", - derive(BorshSerialize, BorshDeserialize, BorshSchema), - borsh(crate = "borsh") -)] -#[cfg_attr( - feature = "serde", - derive(serde_derive::Deserialize, serde_derive::Serialize) -)] -#[derive(Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[repr(transparent)] -pub struct Hash(pub [u8; HASH_BYTES]); - -#[cfg(any(feature = "sha3", not(target_os = "solana")))] #[derive(Clone, Default)] +#[cfg(all(feature = "sha3", not(target_os = "solana")))] pub struct Hasher { hasher: Keccak256, } -#[cfg(any(feature = "sha3", not(target_os = "solana")))] +#[cfg(all(feature = "sha3", not(target_os = "solana")))] impl Hasher { pub fn hash(&mut self, val: &[u8]) { self.hasher.update(val); @@ -56,71 +25,7 @@ impl Hasher { } } pub fn result(self) -> Hash { - Hash(self.hasher.finalize().into()) - } -} - -impl From for Hash { - fn from(val: solana_hash::Hash) -> Self { - Self(val.to_bytes()) - } -} - -impl From for solana_hash::Hash { - fn from(val: Hash) -> Self { - Self::new_from_array(val.0) - } -} - -impl Sanitize for Hash {} - -impl AsRef<[u8]> for Hash { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl fmt::Debug for Hash { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let converted: solana_hash::Hash = (*self).into(); - fmt::Debug::fmt(&converted, f) - } -} - -impl fmt::Display for Hash { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let converted: solana_hash::Hash = (*self).into(); - fmt::Display::fmt(&converted, f) - } -} - -impl FromStr for Hash { - type Err = ParseHashError; - - fn from_str(s: &str) -> Result { - let unconverted = solana_hash::Hash::from_str(s)?; - Ok(unconverted.into()) - } -} - -impl Hash { - #[deprecated(since = "2.2.0", note = "Use 'Hash::new_from_array' instead")] - pub fn new(hash_slice: &[u8]) -> Self { - #[allow(deprecated)] - Self::from(solana_hash::Hash::new(hash_slice)) - } - - pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self { - Self(hash_array) - } - - /// unique Hash for tests and benchmarks. - pub fn new_unique() -> Self { - Self::from(solana_hash::Hash::new_unique()) - } - - pub fn to_bytes(self) -> [u8; HASH_BYTES] { - self.0 + Hash::new_from_array(self.hasher.finalize().into()) } } @@ -130,9 +35,17 @@ pub fn hashv(vals: &[&[u8]]) -> Hash { // not supported #[cfg(not(target_os = "solana"))] { - let mut hasher = Hasher::default(); - hasher.hashv(vals); - hasher.result() + #[cfg(feature = "sha3")] + { + let mut hasher = Hasher::default(); + hasher.hashv(vals); + hasher.result() + } + #[cfg(not(feature = "sha3"))] + { + core::hint::black_box(vals); + panic!("hashv is only available on target `solana` or with the `sha3` feature enabled on this crate") + } } // Call via a system call to perform the calculation #[cfg(target_os = "solana")] @@ -153,11 +66,3 @@ pub fn hashv(vals: &[&[u8]]) -> Hash { pub fn hash(val: &[u8]) -> Hash { hashv(&[val]) } - -#[cfg(feature = "std")] -/// Return the hash of the given hash extended with the given value. -pub fn extend_and_hash(id: &Hash, val: &[u8]) -> Hash { - let mut hash_data = id.as_ref().to_vec(); - hash_data.extend_from_slice(val); - hash(&hash_data) -} diff --git a/keypair/Cargo.toml b/keypair/Cargo.toml index d70683b3f..ec1a871d9 100644 --- a/keypair/Cargo.toml +++ b/keypair/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-keypair" description = "Concrete implementation of a Solana `Signer`." documentation = "https://docs.rs/solana-keypair" version = "2.2.3" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -10,7 +11,7 @@ license = { workspace = true } edition = { workspace = true } [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +targets = ["x86_64-unknown-linux-gnu"] all-features = true rustdoc-args = ["--cfg=docsrs"] @@ -22,10 +23,10 @@ seed-derivable = [ ] [dependencies] -ed25519-dalek = { workspace = true } +ed25519-dalek = { workspace = true, features = ["rand_core"] } ed25519-dalek-bip32 = { workspace = true, optional = true } five8 = { workspace = true } -rand0-7 = { workspace = true } +rand = { workspace = true } solana-derivation-path = { workspace = true, optional = true } solana-pubkey = { workspace = true } solana-seed-derivable = { workspace = true, optional = true } @@ -33,9 +34,6 @@ solana-seed-phrase = { workspace = true } solana-signature = { workspace = true, features = ["std", "verify"] } solana-signer = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -wasm-bindgen = { workspace = true } - [dev-dependencies] serde_json = { workspace = true } static_assertions = { workspace = true } diff --git a/keypair/src/lib.rs b/keypair/src/lib.rs index 3ce31bec2..9ee083440 100644 --- a/keypair/src/lib.rs +++ b/keypair/src/lib.rs @@ -1,10 +1,8 @@ //! Concrete implementation of a Solana `Signer` from raw bytes #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#[cfg(target_arch = "wasm32")] -use wasm_bindgen::prelude::*; use { ed25519_dalek::Signer as DalekSigner, - rand0_7::{rngs::OsRng, CryptoRng, RngCore}, + rand::rngs::OsRng, solana_pubkey::Pubkey, solana_seed_phrase::generate_seed_from_seed_phrase_and_passphrase, solana_signature::{error::Error as SignatureError, Signature}, @@ -21,9 +19,8 @@ pub mod seed_derivable; pub mod signable; /// A vanilla Ed25519 key pair -#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] #[derive(Debug)] -pub struct Keypair(ed25519_dalek::Keypair); +pub struct Keypair(ed25519_dalek::SigningKey); pub const KEYPAIR_LENGTH: usize = 64; @@ -31,41 +28,21 @@ impl Keypair { /// Can be used for generating a Keypair without a dependency on `rand` types pub const SECRET_KEY_LENGTH: usize = 32; - /// Constructs a new, random `Keypair` using a caller-provided RNG - #[deprecated( - since = "2.2.2", - note = "Use `Keypair::new()` instead or generate 32 random bytes and use `Keypair::new_from_array`" - )] - pub fn generate(csprng: &mut R) -> Self - where - R: CryptoRng + RngCore, - { - Self(ed25519_dalek::Keypair::generate(csprng)) - } - /// Constructs a new, random `Keypair` using `OsRng` + #[allow(clippy::new_without_default)] pub fn new() -> Self { let mut rng = OsRng; - Self(ed25519_dalek::Keypair::generate(&mut rng)) + Self(ed25519_dalek::SigningKey::generate(&mut rng)) } /// Constructs a new `Keypair` using secret key bytes pub fn new_from_array(secret_key: [u8; 32]) -> Self { - // unwrap is safe because the only error condition is an incorrect length - let secret = ed25519_dalek::SecretKey::from_bytes(&secret_key).unwrap(); - let public = ed25519_dalek::PublicKey::from(&secret); - Self(ed25519_dalek::Keypair { secret, public }) - } - - /// Recovers a `Keypair` from a byte array - #[deprecated(since = "2.2.2", note = "Use Keypair::try_from(&[u8]) instead")] - pub fn from_bytes(bytes: &[u8]) -> Result { - Self::try_from(bytes).map_err(ed25519_dalek::SignatureError::from_source) + Self(ed25519_dalek::SigningKey::from(secret_key)) } /// Returns this `Keypair` as a byte array pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] { - self.0.to_bytes() + self.0.to_keypair_bytes() } /// Recovers a `Keypair` from a base58-encoded string @@ -78,19 +55,13 @@ impl Keypair { /// Returns this `Keypair` as a base58-encoded string pub fn to_base58_string(&self) -> String { let mut out = [0u8; five8::BASE58_ENCODED_64_MAX_LEN]; - let len = five8::encode_64(&self.0.to_bytes(), &mut out); + let len = five8::encode_64(&self.to_bytes(), &mut out); unsafe { String::from_utf8_unchecked(out[..len as usize].to_vec()) } } - /// Gets this `Keypair`'s SecretKey - #[deprecated(since = "2.2.2", note = "Use secret_bytes()")] - pub fn secret(&self) -> &ed25519_dalek::SecretKey { - &self.0.secret - } - /// Gets this `Keypair`'s secret key bytes pub fn secret_bytes(&self) -> &[u8; Self::SECRET_KEY_LENGTH] { - self.0.secret.as_bytes() + self.0.as_bytes() } /// Allows Keypair cloning @@ -101,11 +72,7 @@ impl Keypair { /// Only use this in tests or when strictly required. Consider using [`std::sync::Arc`] /// instead. pub fn insecure_clone(&self) -> Self { - Self(ed25519_dalek::Keypair { - // This will never error since self is a valid keypair - secret: ed25519_dalek::SecretKey::from_bytes(self.0.secret.as_bytes()).unwrap(), - public: self.0.public, - }) + Self(self.0.clone()) } } @@ -113,60 +80,19 @@ impl TryFrom<&[u8]> for Keypair { type Error = SignatureError; fn try_from(bytes: &[u8]) -> Result { - if bytes.len() < ed25519_dalek::KEYPAIR_LENGTH { - return Err(SignatureError::from_source(String::from( - "candidate keypair byte array is too short", - ))); - } - let secret = - ed25519_dalek::SecretKey::from_bytes(&bytes[..ed25519_dalek::SECRET_KEY_LENGTH]) - .map_err(SignatureError::from_source)?; - let public = - ed25519_dalek::PublicKey::from_bytes(&bytes[ed25519_dalek::SECRET_KEY_LENGTH..]) - .map_err(SignatureError::from_source)?; - let expected_public = ed25519_dalek::PublicKey::from(&secret); - (public == expected_public) - .then_some(Self(ed25519_dalek::Keypair { secret, public })) - .ok_or(SignatureError::from_source(String::from( - "keypair bytes do not specify same pubkey as derived from their secret key", - ))) - } -} - -#[cfg(target_arch = "wasm32")] -#[allow(non_snake_case)] -#[wasm_bindgen] -impl Keypair { - /// Create a new `Keypair ` - #[wasm_bindgen(constructor)] - pub fn constructor() -> Keypair { - Keypair::new() - } - - /// Convert a `Keypair` to a `Uint8Array` - pub fn toBytes(&self) -> Box<[u8]> { - self.to_bytes().into() - } - - /// Recover a `Keypair` from a `Uint8Array` - pub fn fromBytes(bytes: &[u8]) -> Result { - Keypair::try_from(bytes).map_err(|e| e.to_string().into()) - } - - /// Return the `Pubkey` for this `Keypair` - #[wasm_bindgen(js_name = pubkey)] - pub fn js_pubkey(&self) -> Pubkey { - // `wasm_bindgen` does not support traits (`Signer) yet - self.pubkey() - } -} - -// This should also be marked deprecated, but it's not possible to put a -// `#[deprecated]` attribute on a trait implementation. -// Remove during the next major version bump. -impl From for Keypair { - fn from(value: ed25519_dalek::Keypair) -> Self { - Self(value) + let keypair_bytes: &[u8; ed25519_dalek::KEYPAIR_LENGTH] = + bytes.try_into().map_err(|_| { + SignatureError::from_source(String::from( + "candidate keypair byte array is the wrong length", + )) + })?; + ed25519_dalek::SigningKey::from_keypair_bytes(keypair_bytes) + .map_err(|_| { + SignatureError::from_source(String::from( + "keypair bytes do not specify same pubkey as derived from their secret key", + )) + }) + .map(Self) } } @@ -176,7 +102,7 @@ static_assertions::const_assert_eq!(Keypair::SECRET_KEY_LENGTH, ed25519_dalek::S impl Signer for Keypair { #[inline] fn pubkey(&self) -> Pubkey { - Pubkey::from(self.0.public.to_bytes()) + Pubkey::from(self.0.verifying_key().to_bytes()) } fn try_pubkey(&self) -> Result { @@ -272,7 +198,7 @@ pub fn write_keypair( keypair: &Keypair, writer: &mut W, ) -> Result> { - let keypair_bytes = keypair.0.to_bytes(); + let keypair_bytes = keypair.to_bytes(); let mut result = Vec::with_capacity(64 * 4 + 2); // Estimate capacity: 64 numbers * (up to 3 digits + 1 comma) + 2 brackets result.push(b'['); // Opening bracket @@ -306,17 +232,15 @@ pub fn keypair_from_seed(seed: &[u8]) -> Result> if seed.len() < ed25519_dalek::SECRET_KEY_LENGTH { return Err("Seed is too short".into()); } - let secret = ed25519_dalek::SecretKey::from_bytes(&seed[..ed25519_dalek::SECRET_KEY_LENGTH]) - .map_err(|e| e.to_string())?; - let public = ed25519_dalek::PublicKey::from(&secret); - let dalek_keypair = ed25519_dalek::Keypair { secret, public }; - Ok(Keypair(dalek_keypair)) + // this won't fail as we've already checked the length + let secret_key = ed25519_dalek::SecretKey::try_from(&seed[..ed25519_dalek::SECRET_KEY_LENGTH])?; + Ok(Keypair(ed25519_dalek::SigningKey::from(secret_key))) } pub fn keypair_from_seed_phrase_and_passphrase( seed_phrase: &str, passphrase: &str, -) -> Result> { +) -> Result> { keypair_from_seed(&generate_seed_from_seed_phrase_and_passphrase( seed_phrase, passphrase, @@ -351,7 +275,7 @@ mod tests { assert!(Path::new(&outfile).exists()); assert_eq!( keypair_vec, - read_keypair_file(&outfile).unwrap().0.to_bytes().to_vec() + read_keypair_file(&outfile).unwrap().to_bytes().to_vec() ); #[cfg(unix)] @@ -490,4 +414,12 @@ mod tests { keypair_from_seed_phrase_and_passphrase(mnemonic.phrase(), passphrase).unwrap(); assert_eq!(keypair.pubkey(), expected_keypair.pubkey()); } + + #[test] + fn test_base58() { + let keypair = keypair_from_seed(&[0u8; 32]).unwrap(); + let as_base58 = keypair.to_base58_string(); + let parsed = Keypair::from_base58_string(&as_base58); + assert_eq!(keypair, parsed); + } } diff --git a/keypair/src/seed_derivable.rs b/keypair/src/seed_derivable.rs index 4f530f41f..b211e3a72 100644 --- a/keypair/src/seed_derivable.rs +++ b/keypair/src/seed_derivable.rs @@ -43,11 +43,7 @@ fn bip32_derived_keypair( seed: &[u8], derivation_path: DerivationPath, ) -> Result { - let extended = ed25519_dalek_bip32::ExtendedSecretKey::from_seed(seed) + let extended = ed25519_dalek_bip32::ExtendedSigningKey::from_seed(seed) .and_then(|extended| extended.derive(&derivation_path))?; - let extended_public_key = extended.public_key(); - Ok(Keypair::from(ed25519_dalek::Keypair { - secret: extended.secret_key, - public: extended_public_key, - })) + Ok(Keypair(extended.signing_key)) } diff --git a/keypair/src/signable.rs b/keypair/src/signable.rs index 782af4200..4211936d5 100644 --- a/keypair/src/signable.rs +++ b/keypair/src/signable.rs @@ -17,7 +17,7 @@ pub trait Signable { } fn pubkey(&self) -> Pubkey; - fn signable_data(&self) -> Cow<[u8]>; + fn signable_data(&self) -> Cow<'_, [u8]>; fn get_signature(&self) -> Signature; fn set_signature(&mut self, signature: Signature); } diff --git a/logger/Cargo.toml b/logger/Cargo.toml index 914e18265..4634c3d63 100644 --- a/logger/Cargo.toml +++ b/logger/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-logger" description = "Solana Logger" documentation = "https://docs.rs/solana-logger" -version = "2.3.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/message/Cargo.toml b/message/Cargo.toml index 1670abd22..3686c1f80 100644 --- a/message/Cargo.toml +++ b/message/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-message" description = "Solana transaction message types." documentation = "https://docs.rs/solana-message" version = "2.4.0" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -10,17 +11,12 @@ license = { workspace = true } edition = { workspace = true } [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +targets = ["x86_64-unknown-linux-gnu"] all-features = true rustdoc-args = ["--cfg=docsrs"] [features] -bincode = [ - "dep:bincode", - "dep:solana-bincode", - "dep:solana-system-interface", - "serde", -] +bincode = ["dep:bincode", "serde"] blake3 = ["dep:blake3"] dev-context-only-utils = ["bincode", "blake3"] frozen-abi = [ @@ -45,7 +41,6 @@ blake3 = { workspace = true, features = ["traits-preview"], optional = true } lazy_static = { workspace = true } serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } -solana-bincode = { workspace = true, optional = true } solana-frozen-abi = { workspace = true, optional = true } solana-frozen-abi-macro = { workspace = true, optional = true } solana-hash = { workspace = true } @@ -55,25 +50,21 @@ solana-pubkey = { workspace = true } solana-sanitize = { workspace = true } solana-sdk-ids = { workspace = true } solana-short-vec = { workspace = true, optional = true } -solana-system-interface = { workspace = true, optional = true, features = [ - "bincode", -] } solana-transaction-error = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -wasm-bindgen = { workspace = true } - [dev-dependencies] anyhow = { workspace = true } bitflags = { workspace = true } borsh = { workspace = true } itertools = { workspace = true } serde_json = { workspace = true } +solana-address-lookup-table-interface = { workspace = true, features = ["bincode", "bytemuck"] } +solana-example-mocks = { path = "../example-mocks" } +solana-instruction = { workspace = true, features = ["borsh"] } +solana-instruction-error = { workspace = true } solana-message = { path = ".", features = ["dev-context-only-utils"] } solana-nonce = { workspace = true } -solana-program = { path = "../program" } -solana-sha256-hasher = { workspace = true } -solana-sysvar = { workspace = true } +solana-system-interface = { workspace = true, features = ["bincode"] } static_assertions = { workspace = true } [lints] diff --git a/message/src/address_loader.rs b/message/src/address_loader.rs index 82ac882a7..21bffdeec 100644 --- a/message/src/address_loader.rs +++ b/message/src/address_loader.rs @@ -1,9 +1,7 @@ -use crate::v0::{LoadedAddresses, MessageAddressTableLookup}; -#[deprecated( - since = "2.1.0", - note = "Use solana_transaction_error::AddressLoaderError instead" -)] -pub use solana_transaction_error::AddressLoaderError; +use { + crate::v0::{LoadedAddresses, MessageAddressTableLookup}, + solana_transaction_error::AddressLoaderError, +}; pub trait AddressLoader: Clone { fn load_addresses( diff --git a/message/src/compiled_keys.rs b/message/src/compiled_keys.rs index 91928e905..354b93782 100644 --- a/message/src/compiled_keys.rs +++ b/message/src/compiled_keys.rs @@ -4,8 +4,12 @@ use crate::{ AddressLookupTableAccount, }; use { - crate::MessageHeader, core::fmt, solana_instruction::Instruction, solana_pubkey::Pubkey, - solana_sdk_ids::system_program, std::collections::BTreeMap, + crate::{inline_nonce::is_advance_nonce_instruction_data, MessageHeader}, + core::fmt, + solana_instruction::Instruction, + solana_pubkey::Pubkey, + solana_sdk_ids::system_program, + std::collections::BTreeMap, }; /// A helper struct to collect pubkeys compiled for a set of instructions @@ -23,7 +27,7 @@ pub enum CompileError { UnknownInstructionKey(Pubkey), } -impl std::error::Error for CompileError {} +impl core::error::Error for CompileError {} impl fmt::Display for CompileError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -35,8 +39,7 @@ impl fmt::Display for CompileError { f.write_str("address lookup table index overflowed during compilation") } CompileError::UnknownInstructionKey(key) => f.write_fmt(format_args!( - "encountered unknown account key `{0}` during instruction compilation", - key, + "encountered unknown account key `{key}` during instruction compilation", )), } } @@ -204,8 +207,6 @@ impl CompiledKeys { // inlined to avoid solana_nonce dep const NONCED_TX_MARKER_IX_INDEX: usize = 0; -// inlined to avoid solana_system_interface and bincode deps -const ADVANCE_NONCE_PREFIX: [u8; 4] = [4, 0, 0, 0]; fn get_nonce_pubkey(instructions: &[Instruction]) -> Option<&Pubkey> { let ix = instructions.get(NONCED_TX_MARKER_IX_INDEX)?; @@ -213,7 +214,7 @@ fn get_nonce_pubkey(instructions: &[Instruction]) -> Option<&Pubkey> { return None; } - if ix.data.get(0..4) != Some(&ADVANCE_NONCE_PREFIX[..]) { + if !is_advance_nonce_instruction_data(&ix.data) { return None; } @@ -223,11 +224,9 @@ fn get_nonce_pubkey(instructions: &[Instruction]) -> Option<&Pubkey> { #[cfg(test)] mod tests { use { - super::*, - bitflags::bitflags, - solana_instruction::AccountMeta, + super::*, bitflags::bitflags, solana_instruction::AccountMeta, solana_sdk_ids::sysvar::recent_blockhashes, - solana_system_interface::instruction::{advance_nonce_account, SystemInstruction}, + solana_system_interface::instruction::advance_nonce_account, }; static_assertions::const_assert_eq!( @@ -256,16 +255,6 @@ mod tests { } } - #[test] - fn test_advance_nonce_ix_prefix() { - let advance_nonce_ix: SystemInstruction = solana_bincode::limited_deserialize( - &ADVANCE_NONCE_PREFIX[..], - 4, /* serialized size of AdvanceNonceAccount */ - ) - .unwrap(); - assert_eq!(advance_nonce_ix, SystemInstruction::AdvanceNonceAccount); - } - #[test] fn test_compile_with_dups() { let program_id0 = Pubkey::new_unique(); diff --git a/message/src/inline_nonce.rs b/message/src/inline_nonce.rs new file mode 100644 index 000000000..401853596 --- /dev/null +++ b/message/src/inline_nonce.rs @@ -0,0 +1,63 @@ +//! Inlined nonce instruction information to avoid a dependency on bincode and +//! solana-system-interface +use { + solana_instruction::{AccountMeta, Instruction}, + solana_pubkey::Pubkey, + solana_sdk_ids::{system_program, sysvar}, +}; + +/// Inlined `SystemInstruction::AdvanceNonceAccount` instruction data to avoid +/// solana_system_interface and bincode deps +const ADVANCE_NONCE_DATA: [u8; 4] = [4, 0, 0, 0]; + +/// Check if the given instruction data is the same as +/// `SystemInstruction::AdvanceNonceAccount`. +/// +/// NOTE: It's possible for additional data to exist after the 4th byte, but +/// users of this function only look at the first 4 bytes. +pub fn is_advance_nonce_instruction_data(data: &[u8]) -> bool { + data.get(0..4) == Some(&ADVANCE_NONCE_DATA) +} + +/// Inlined `advance_nonce_account` instruction creator to avoid +/// solana_system_interface and bincode deps +pub(crate) fn advance_nonce_account_instruction( + nonce_pubkey: &Pubkey, + nonce_authority_pubkey: &Pubkey, +) -> Instruction { + Instruction::new_with_bytes( + system_program::id(), + &ADVANCE_NONCE_DATA, + vec![ + AccountMeta::new(*nonce_pubkey, false), + #[allow(deprecated)] + AccountMeta::new_readonly(sysvar::recent_blockhashes::id(), false), + AccountMeta::new_readonly(*nonce_authority_pubkey, true), + ], + ) +} + +#[cfg(test)] +mod test { + use { + super::*, + solana_system_interface::instruction::{advance_nonce_account, SystemInstruction}, + }; + + #[test] + fn inline_instruction_data_matches_program() { + let nonce = Pubkey::new_unique(); + let nonce_authority = Pubkey::new_unique(); + assert_eq!( + advance_nonce_account_instruction(&nonce, &nonce_authority), + advance_nonce_account(&nonce, &nonce_authority), + ); + } + + #[test] + fn test_advance_nonce_ix_prefix() { + let advance_nonce_ix: SystemInstruction = + bincode::deserialize(&ADVANCE_NONCE_DATA).unwrap(); + assert_eq!(advance_nonce_ix, SystemInstruction::AdvanceNonceAccount); + } +} diff --git a/message/src/legacy.rs b/message/src/legacy.rs index 3b2f7def3..637883ad6 100644 --- a/message/src/legacy.rs +++ b/message/src/legacy.rs @@ -11,105 +11,23 @@ #![allow(clippy::arithmetic_side_effects)] -#[allow(deprecated)] -pub use builtins::{BUILTIN_PROGRAMS_KEYS, MAYBE_BUILTIN_KEY_OR_SYSVAR}; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; -#[cfg(target_arch = "wasm32")] -use wasm_bindgen::prelude::wasm_bindgen; use { crate::{ - compiled_instruction::CompiledInstruction, compiled_keys::CompiledKeys, MessageHeader, + compiled_instruction::CompiledInstruction, compiled_keys::CompiledKeys, + inline_nonce::advance_nonce_account_instruction, MessageHeader, }, solana_hash::Hash, solana_instruction::Instruction, solana_pubkey::Pubkey, solana_sanitize::{Sanitize, SanitizeError}, - solana_sdk_ids::{ - bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, system_program, sysvar, - }, - std::{collections::HashSet, convert::TryFrom, str::FromStr}, + solana_sdk_ids::bpf_loader_upgradeable, + std::{collections::HashSet, convert::TryFrom}, }; -// copied from deprecated code in solana_program::sysvar to avoid a dependency. -// This should be removed when the items that depend on it are removed. -lazy_static::lazy_static! { - // This will be deprecated and so this list shouldn't be modified - static ref ALL_IDS: Vec = vec![ - sysvar::clock::id(), - sysvar::epoch_schedule::id(), - sysvar::fees::id(), - sysvar::recent_blockhashes::id(), - sysvar::rent::id(), - sysvar::rewards::id(), - sysvar::slot_hashes::id(), - sysvar::slot_history::id(), - sysvar::stake_history::id(), - sysvar::instructions::id(), - ]; -} - -// copied from deprecated code in solana_program::sysvar to avoid a dependency. -// This should be removed when the items that depend on it are removed. -fn is_sysvar_id(id: &Pubkey) -> bool { - ALL_IDS.iter().any(|key| key == id) -} - -#[deprecated( - since = "2.0.0", - note = "please use `solana_sdk::reserved_account_keys::ReservedAccountKeys` instead" -)] -#[allow(deprecated)] -mod builtins { - use {super::*, lazy_static::lazy_static}; - - lazy_static! { - pub static ref BUILTIN_PROGRAMS_KEYS: [Pubkey; 10] = { - let parse = |s| Pubkey::from_str(s).unwrap(); - [ - parse("Config1111111111111111111111111111111111111"), - parse("Feature111111111111111111111111111111111111"), - parse("NativeLoader1111111111111111111111111111111"), - parse("Stake11111111111111111111111111111111111111"), - parse("StakeConfig11111111111111111111111111111111"), - parse("Vote111111111111111111111111111111111111111"), - system_program::id(), - bpf_loader::id(), - bpf_loader_deprecated::id(), - bpf_loader_upgradeable::id(), - ] - }; - } - - lazy_static! { - // Each element of a key is a u8. We use key[0] as an index into this table of 256 boolean - // elements, to store whether or not the first element of any key is present in the static - // lists of built-in-program keys or system ids. By using this lookup table, we can very - // quickly determine that a key under consideration cannot be in either of these lists (if - // the value is "false"), or might be in one of these lists (if the value is "true") - pub static ref MAYBE_BUILTIN_KEY_OR_SYSVAR: [bool; 256] = { - let mut temp_table: [bool; 256] = [false; 256]; - BUILTIN_PROGRAMS_KEYS.iter().for_each(|key| temp_table[key.as_ref()[0] as usize] = true); - ALL_IDS.iter().for_each(|key| temp_table[key.as_ref()[0] as usize] = true); - temp_table - }; - } -} - -#[deprecated( - since = "2.0.0", - note = "please use `solana_sdk::reserved_account_keys::ReservedAccountKeys::is_reserved` instead" -)] -#[allow(deprecated)] -pub fn is_builtin_key_or_sysvar(key: &Pubkey) -> bool { - if MAYBE_BUILTIN_KEY_OR_SYSVAR[key.as_ref()[0] as usize] { - return is_sysvar_id(key) || BUILTIN_PROGRAMS_KEYS.contains(key); - } - false -} - fn position(keys: &[Pubkey], key: &Pubkey) -> u8 { keys.iter().position(|k| k == key).unwrap() as u8 } @@ -146,10 +64,9 @@ fn compile_instructions(ixs: &[Instruction], keys: &[Pubkey]) -> Vec, } -/// wasm-bindgen version of the Message struct. -/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671 -/// is fixed. This must not diverge from the regular non-wasm Message struct. -#[cfg(target_arch = "wasm32")] -#[wasm_bindgen] -#[cfg_attr( - feature = "frozen-abi", - frozen_abi(digest = "2THeaWnXSGDTsiadKytJTcbjrk4KjfMww9arRLZcwGnw"), - derive(AbiExample) -)] -#[cfg_attr( - feature = "serde", - derive(Deserialize, Serialize), - serde(rename_all = "camelCase") -)] -#[derive(Default, Debug, PartialEq, Eq, Clone)] -pub struct Message { - #[wasm_bindgen(skip)] - pub header: MessageHeader, - - #[wasm_bindgen(skip)] - #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] - pub account_keys: Vec, - - /// The id of a recent ledger entry. - pub recent_blockhash: Hash, - - #[wasm_bindgen(skip)] - #[cfg_attr(feature = "serde", serde(with = "solana_short_vec"))] - pub instructions: Vec, -} - impl Sanitize for Message { fn sanitize(&self) -> std::result::Result<(), SanitizeError> { // signing area and read-only non-signing area should not overlap @@ -256,18 +141,17 @@ impl Message { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_program::example_mocks::solana_sdk; - /// # use solana_program::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_signer, solana_transaction}; + /// # use solana_example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; /// use solana_message::Message; /// use solana_pubkey::Pubkey; /// use solana_rpc_client::rpc_client::RpcClient; - /// use solana_sdk::{ - /// signature::{Keypair, Signer}, - /// transaction::Transaction, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -328,18 +212,17 @@ impl Message { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_program::example_mocks::solana_sdk; - /// # use solana_program::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_signer, solana_transaction}; + /// # use solana_example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; /// use solana_message::Message; /// use solana_pubkey::Pubkey; /// use solana_rpc_client::rpc_client::RpcClient; - /// use solana_sdk::{ - /// signature::{Keypair, Signer}, - /// transaction::Transaction, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// /// // A custom program instruction. This would typically be defined in /// // another crate so it can be shared between the on-chain program and @@ -425,19 +308,18 @@ impl Message { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_program::example_mocks::solana_sdk; - /// # use solana_program::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_signer, solana_transaction}; + /// # use solana_example_mocks::solana_rpc_client; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_hash::Hash; /// use solana_instruction::Instruction; + /// use solana_keypair::Keypair; /// use solana_message::Message; /// use solana_pubkey::Pubkey; /// use solana_rpc_client::rpc_client::RpcClient; - /// use solana_sdk::{ - /// signature::{Keypair, Signer}, - /// transaction::Transaction, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::Transaction; /// use solana_system_interface::instruction::create_nonce_account; /// /// // A custom program instruction. This would typically be defined in @@ -514,17 +396,14 @@ impl Message { /// # create_offline_initialize_tx(&client, program_id, &payer)?; /// # Ok::<(), anyhow::Error>(()) /// ``` - #[cfg(feature = "bincode")] pub fn new_with_nonce( mut instructions: Vec, payer: Option<&Pubkey>, nonce_account_pubkey: &Pubkey, nonce_authority_pubkey: &Pubkey, ) -> Self { - let nonce_ix = solana_system_interface::instruction::advance_nonce_account( - nonce_account_pubkey, - nonce_authority_pubkey, - ); + let nonce_ix = + advance_nonce_account_instruction(nonce_account_pubkey, nonce_authority_pubkey); instructions.insert(0, nonce_ix); Self::new(&instructions, payer) } @@ -593,11 +472,6 @@ impl Message { .collect() } - #[deprecated(since = "2.0.0", note = "Please use `is_instruction_account` instead")] - pub fn is_key_passed_to_program(&self, key_index: usize) -> bool { - self.is_instruction_account(key_index) - } - /// Returns true if the account at the specified index is an account input /// to some program instruction in this message. pub fn is_instruction_account(&self, key_index: usize) -> bool { @@ -620,14 +494,6 @@ impl Message { } } - #[deprecated( - since = "2.0.0", - note = "Please use `is_key_called_as_program` and `is_instruction_account` directly" - )] - pub fn is_non_loader_key(&self, key_index: usize) -> bool { - !self.is_key_called_as_program(key_index) || self.is_instruction_account(key_index) - } - pub fn program_position(&self, index: usize) -> Option { let program_ids = self.program_ids(); program_ids @@ -655,18 +521,6 @@ impl Message { .saturating_sub(self.header.num_readonly_unsigned_accounts as usize)) } - /// Returns true if the account at the specified index is writable by the - /// instructions in this message. Since the dynamic set of reserved accounts - /// isn't used here to demote write locks, this shouldn't be used in the - /// runtime. - #[deprecated(since = "2.0.0", note = "Please use `is_maybe_writable` instead")] - #[allow(deprecated)] - pub fn is_writable(&self, i: usize) -> bool { - (self.is_writable_index(i)) - && !is_builtin_key_or_sysvar(&self.account_keys[i]) - && !self.demote_program_id(i) - } - /// Returns true if the account at the specified index is writable by the /// instructions in this message. The `reserved_account_keys` param has been /// optional to allow clients to approximate writability without requiring @@ -736,33 +590,13 @@ impl Message { #[cfg(test)] mod tests { - #![allow(deprecated)] use { - super::*, crate::MESSAGE_HEADER_LENGTH, solana_instruction::AccountMeta, - solana_sha256_hasher::hash, std::collections::HashSet, + super::*, + crate::MESSAGE_HEADER_LENGTH, + solana_instruction::AccountMeta, + std::{collections::HashSet, str::FromStr}, }; - #[test] - fn test_builtin_program_keys() { - let keys: HashSet = BUILTIN_PROGRAMS_KEYS.iter().copied().collect(); - assert_eq!(keys.len(), 10); - for k in keys { - let k = format!("{k}"); - assert!(k.ends_with("11111111111111111111111")); - } - } - - #[test] - fn test_builtin_program_keys_abi_freeze() { - // Once the feature is flipped on, we can't further modify - // BUILTIN_PROGRAMS_KEYS without the risk of breaking consensus. - let builtins = format!("{:?}", *BUILTIN_PROGRAMS_KEYS); - assert_eq!( - format!("{}", hash(builtins.as_bytes())), - "ACqmMkYbo9eqK6QrRSrB3HLyR6uHhLf31SCfGUAJjiWj" - ); - } - #[test] // Ensure there's a way to calculate the number of required signatures. fn test_message_signed_keys_len() { @@ -845,33 +679,6 @@ mod tests { assert_eq!(message.program_position(2), Some(1)); } - #[test] - fn test_is_writable() { - let key0 = Pubkey::new_unique(); - let key1 = Pubkey::new_unique(); - let key2 = Pubkey::new_unique(); - let key3 = Pubkey::new_unique(); - let key4 = Pubkey::new_unique(); - let key5 = Pubkey::new_unique(); - - let message = Message { - header: MessageHeader { - num_required_signatures: 3, - num_readonly_signed_accounts: 2, - num_readonly_unsigned_accounts: 1, - }, - account_keys: vec![key0, key1, key2, key3, key4, key5], - recent_blockhash: Hash::default(), - instructions: vec![], - }; - assert!(message.is_writable(0)); - assert!(!message.is_writable(1)); - assert!(!message.is_writable(2)); - assert!(message.is_writable(3)); - assert!(message.is_writable(4)); - assert!(!message.is_writable(5)); - } - #[test] fn test_is_maybe_writable() { let key0 = Pubkey::new_unique(); @@ -961,26 +768,6 @@ mod tests { assert!(!message.is_instruction_account(2)); } - #[test] - fn test_is_non_loader_key() { - #![allow(deprecated)] - let key0 = Pubkey::new_unique(); - let key1 = Pubkey::new_unique(); - let loader2 = Pubkey::new_unique(); - let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])]; - let message = Message::new_with_compiled_instructions( - 1, - 0, - 2, - vec![key0, key1, loader2], - Hash::default(), - instructions, - ); - assert!(message.is_non_loader_key(0)); - assert!(message.is_non_loader_key(1)); - assert!(!message.is_non_loader_key(2)); - } - #[test] fn test_message_header_len_constant() { assert_eq!( @@ -1021,11 +808,6 @@ mod tests { ) } - #[test] - fn test_inline_all_ids() { - assert_eq!(solana_sysvar::ALL_IDS.to_vec(), ALL_IDS.to_vec()); - } - #[test] fn test_is_writable_index_saturating_behavior() { // Directly matching issue #150 PoC 1: diff --git a/message/src/lib.rs b/message/src/lib.rs index f41fc2afc..cc6adf291 100644 --- a/message/src/lib.rs +++ b/message/src/lib.rs @@ -41,6 +41,7 @@ pub mod compiled_instruction; mod compiled_keys; +pub mod inline_nonce; pub mod inner_instruction; pub mod legacy; #[cfg(feature = "serde")] diff --git a/message/src/sanitized.rs b/message/src/sanitized.rs index 92f6e23f5..ba74fb1f6 100644 --- a/message/src/sanitized.rs +++ b/message/src/sanitized.rs @@ -1,8 +1,3 @@ -#[deprecated( - since = "2.1.0", - note = "Use solana_transaction_error::SanitizeMessageError instead" -)] -pub use solana_transaction_error::SanitizeMessageError; use { crate::{ compiled_instruction::CompiledInstruction, @@ -15,11 +10,11 @@ use { solana_pubkey::Pubkey, solana_sanitize::Sanitize, solana_sdk_ids::{ed25519_program, secp256k1_program, secp256r1_program}, + solana_transaction_error::SanitizeMessageError, std::{borrow::Cow, collections::HashSet, convert::TryFrom}, }; // inlined to avoid solana_nonce dep -#[cfg(feature = "bincode")] const NONCED_TX_MARKER_IX_INDEX: u8 = 0; #[cfg(test)] static_assertions::const_assert_eq!( @@ -68,7 +63,7 @@ impl LegacyMessage<'_> { } /// Returns the full list of account keys. - pub fn account_keys(&self) -> AccountKeys { + pub fn account_keys(&self) -> AccountKeys<'_> { AccountKeys::new(&self.message.account_keys, None) } @@ -197,7 +192,7 @@ impl SanitizedMessage { } /// Returns the list of account keys that are loaded for this message. - pub fn account_keys(&self) -> AccountKeys { + pub fn account_keys(&self) -> AccountKeys<'_> { match self { Self::Legacy(message) => message.account_keys(), Self::V0(message) => message.account_keys(), @@ -212,13 +207,6 @@ impl SanitizedMessage { } } - /// Returns true if the account at the specified index is an input to some - /// program instruction in this message. - #[deprecated(since = "2.0.0", note = "Please use `is_instruction_account` instead")] - pub fn is_key_passed_to_program(&self, key_index: usize) -> bool { - self.is_instruction_account(key_index) - } - /// Returns true if the account at the specified index is an input to some /// program instruction in this message. pub fn is_instruction_account(&self, key_index: usize) -> bool { @@ -240,16 +228,6 @@ impl SanitizedMessage { } } - /// Returns true if the account at the specified index is not invoked as a - /// program or, if invoked, is passed to a program. - #[deprecated( - since = "2.0.0", - note = "Please use `is_invoked` and `is_instruction_account` instead" - )] - pub fn is_non_loader_key(&self, key_index: usize) -> bool { - !self.is_invoked(key_index) || self.is_instruction_account(key_index) - } - /// Returns true if the account at the specified index is writable by the /// instructions in this message. pub fn is_writable(&self, index: usize) -> bool { @@ -285,7 +263,7 @@ impl SanitizedMessage { } /// Decompile message instructions without cloning account keys - pub fn decompile_instructions(&self) -> Vec { + pub fn decompile_instructions(&self) -> Vec> { let account_keys = self.account_keys(); self.program_instructions_iter() .map(|(program_id, instruction)| { @@ -334,7 +312,6 @@ impl SanitizedMessage { }) } - #[cfg(feature = "bincode")] /// If the message uses a durable nonce, return the pubkey of the nonce account pub fn get_durable_nonce(&self) -> Option<&Pubkey> { self.instructions() @@ -345,14 +322,7 @@ impl SanitizedMessage { _ => false, }, ) - .filter(|ix| { - matches!( - solana_bincode::limited_deserialize( - &ix.data, 4 /* serialized size of AdvanceNonceAccount */ - ), - Ok(solana_system_interface::instruction::SystemInstruction::AdvanceNonceAccount) - ) - }) + .filter(|ix| crate::inline_nonce::is_advance_nonce_instruction_data(&ix.data)) .and_then(|ix| { ix.accounts.first().and_then(|idx| { let idx = *idx as usize; @@ -365,14 +335,6 @@ impl SanitizedMessage { }) } - #[deprecated( - since = "2.1.0", - note = "Please use `SanitizedMessage::num_total_signatures` instead." - )] - pub fn num_signatures(&self) -> u64 { - self.num_total_signatures() - } - /// Returns the total number of signatures in the message. /// This includes required transaction signatures as well as any /// pre-compile signatures that are attached in instructions. @@ -500,35 +462,6 @@ mod tests { ); } - #[test] - fn test_is_non_loader_key() { - #![allow(deprecated)] - let key0 = Pubkey::new_unique(); - let key1 = Pubkey::new_unique(); - let loader_key = Pubkey::new_unique(); - let instructions = vec![ - CompiledInstruction::new(1, &(), vec![0]), - CompiledInstruction::new(2, &(), vec![0, 1]), - ]; - - let message = SanitizedMessage::try_from_legacy_message( - legacy::Message::new_with_compiled_instructions( - 1, - 0, - 2, - vec![key0, key1, loader_key], - Hash::default(), - instructions, - ), - &HashSet::default(), - ) - .unwrap(); - - assert!(message.is_non_loader_key(0)); - assert!(message.is_non_loader_key(1)); - assert!(!message.is_non_loader_key(2)); - } - #[test] fn test_num_readonly_accounts() { let key0 = Pubkey::new_unique(); diff --git a/message/src/versions/mod.rs b/message/src/versions/mod.rs index 99918feff..eb0a50c64 100644 --- a/message/src/versions/mod.rs +++ b/message/src/versions/mod.rs @@ -38,7 +38,7 @@ pub const MESSAGE_VERSION_PREFIX: u8 = 0x80; /// format. #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "2RTtea34NPrb8p9mWHCWjFh76cwP3MbjSmeoj5CXEBwN"), + frozen_abi(digest = "Hndd1SDxQ5qNZvzHo77dpW6uD5c1DJNVjtg8tE6hc432"), derive(AbiEnumVisitor, AbiExample) )] #[derive(Debug, PartialEq, Eq, Clone)] @@ -97,11 +97,6 @@ impl VersionedMessage { } } - #[deprecated(since = "2.0.0", note = "Please use `is_instruction_account` instead")] - pub fn is_key_passed_to_program(&self, key_index: usize) -> bool { - self.is_instruction_account(key_index) - } - /// Returns true if the account at the specified index is an input to some /// program instruction in this message. fn is_instruction_account(&self, key_index: usize) -> bool { diff --git a/message/src/versions/v0/loaded.rs b/message/src/versions/v0/loaded.rs index 94325007e..00c34c28e 100644 --- a/message/src/versions/v0/loaded.rs +++ b/message/src/versions/v0/loaded.rs @@ -98,7 +98,7 @@ impl<'a> LoadedMessage<'a> { } /// Returns the full list of static and dynamic account keys that are loaded for this message. - pub fn account_keys(&self) -> AccountKeys { + pub fn account_keys(&self) -> AccountKeys<'_> { AccountKeys::new(&self.message.account_keys, Some(&self.loaded_addresses)) } diff --git a/message/src/versions/v0/mod.rs b/message/src/versions/v0/mod.rs index 893a0664b..e3f34ea5a 100644 --- a/message/src/versions/v0/mod.rs +++ b/message/src/versions/v0/mod.rs @@ -191,29 +191,31 @@ impl Message { /// /// # Examples /// - /// This example uses the [`solana_rpc_client`], [`solana_sdk`], and [`anyhow`] crates. + /// This example uses the [`solana_rpc_client`], [`solana_account`], and [`anyhow`] crates. /// /// [`solana_rpc_client`]: https://docs.rs/solana-rpc-client - /// [`solana_sdk`]: https://docs.rs/solana-sdk + /// [`solana_account`]: https://docs.rs/solana-account /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_program::example_mocks::{ + /// # use solana_example_mocks::{ /// # solana_rpc_client, - /// # solana_sdk, + /// # solana_account, + /// # solana_transaction, + /// # solana_signer, + /// # solana_keypair, /// # }; /// # use std::borrow::Cow; - /// # use solana_sdk::account::Account; + /// # use solana_account::Account; /// use anyhow::Result; + /// use solana_address_lookup_table_interface::state::{AddressLookupTable, LookupTableMeta}; /// use solana_instruction::{AccountMeta, Instruction}; + /// use solana_keypair::Keypair; /// use solana_message::{AddressLookupTableAccount, VersionedMessage, v0}; /// use solana_pubkey::Pubkey; /// use solana_rpc_client::rpc_client::RpcClient; - /// use solana_program::address_lookup_table::{self, state::{AddressLookupTable, LookupTableMeta}}; - /// use solana_sdk::{ - /// signature::{Keypair, Signer}, - /// transaction::VersionedTransaction, - /// }; + /// use solana_signer::Signer; + /// use solana_transaction::versioned::VersionedTransaction; /// /// fn create_tx_with_address_table_lookup( /// client: &RpcClient, @@ -227,9 +229,8 @@ impl Message { /// # meta: LookupTableMeta::default(), /// # addresses: Cow::Owned(instruction.accounts.iter().map(|meta| meta.pubkey).collect()), /// # }.serialize_for_tests().unwrap(), - /// # owner: address_lookup_table::program::id(), + /// # owner: solana_address_lookup_table_interface::program::id(), /// # executable: false, - /// # rent_epoch: 1, /// # }); /// let raw_account = client.get_account(&address_lookup_table_key)?; /// let address_lookup_table = AddressLookupTable::deserialize(&raw_account.data)?; diff --git a/msg/Cargo.toml b/msg/Cargo.toml index 3a7cc8535..694763349 100644 --- a/msg/Cargo.toml +++ b/msg/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-msg" description = "Solana msg macro." documentation = "https://docs.rs/solana-msg" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -12,6 +12,10 @@ edition = { workspace = true } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] +[features] +default = ["std"] +std = [] + [target.'cfg(target_os = "solana")'.dependencies] solana-define-syscall = { workspace = true } diff --git a/msg/src/lib.rs b/msg/src/lib.rs index 860a4486b..b686e74a3 100644 --- a/msg/src/lib.rs +++ b/msg/src/lib.rs @@ -1,3 +1,6 @@ +#![no_std] +#[cfg(feature = "std")] +extern crate std; /// Print a message to the log. /// /// Supports simple strings as well as Rust [format strings][fs]. When passed a @@ -25,6 +28,7 @@ /// let err = "not enough signers"; /// msg!("multisig failed: {}", err); /// ``` +#[cfg(feature = "std")] #[macro_export] macro_rules! msg { ($msg:expr) => { @@ -44,6 +48,9 @@ pub fn sol_log(message: &str) { syscalls::sol_log_(message.as_ptr(), message.len() as u64); } - #[cfg(not(target_os = "solana"))] - println!("{message}"); + #[cfg(all(not(target_os = "solana"), feature = "std"))] + std::println!("{message}"); + + #[cfg(all(not(target_os = "solana"), not(feature = "std")))] + core::hint::black_box(message); } diff --git a/native-token/Cargo.toml b/native-token/Cargo.toml index a38bb3951..060ee15b8 100644 --- a/native-token/Cargo.toml +++ b/native-token/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-native-token" description = "Definitions for the native SOL token and its fractional lamports." documentation = "https://docs.rs/solana-native-token" -version = "2.3.0" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/native-token/src/lib.rs b/native-token/src/lib.rs index 1763c35b4..c71b62ccf 100644 --- a/native-token/src/lib.rs +++ b/native-token/src/lib.rs @@ -4,26 +4,8 @@ /// There are 10^9 lamports in one SOL pub const LAMPORTS_PER_SOL: u64 = 1_000_000_000; -const LAMPORTS_PER_SOL_F64: f64 = LAMPORTS_PER_SOL as f64; const SOL_DECIMALS: usize = 9; -/// Approximately convert fractional native tokens (lamports) into native tokens (SOL) -#[deprecated( - since = "2.3.0", - note = "solana_cli_output::display::build_balance_message" -)] -pub fn lamports_to_sol(lamports: u64) -> f64 { - lamports as f64 / LAMPORTS_PER_SOL_F64 -} - -/// Approximately convert native tokens (SOL) into fractional native tokens (lamports) -#[deprecated(since = "2.3.0", note = "sol_str_to_lamports")] -pub fn sol_to_lamports(sol: f64) -> u64 { - // NaNs return zero, negative values saturate to u64::MIN (i.e. zero), positive values saturate to u64::MAX - // https://doc.rust-lang.org/reference/expressions/operator-expr.html#r-expr.as.numeric.float-as-int - (sol * LAMPORTS_PER_SOL_F64).round() as u64 -} - /// Convert native tokens (SOL) into fractional native tokens (lamports) pub fn sol_str_to_lamports(sol_str: &str) -> Option { if sol_str == "." { @@ -38,7 +20,7 @@ pub fn sol_str_to_lamports(sol_str: &str) -> Option { let lamports = if lamports.is_empty() { 0 } else { - format!("{:0<9}", lamports)[..SOL_DECIMALS].parse().ok()? + format!("{lamports:0<9}")[..SOL_DECIMALS].parse().ok()? }; LAMPORTS_PER_SOL .checked_mul(sol) @@ -76,76 +58,6 @@ impl Debug for Sol { mod tests { use super::*; - #[test] - #[allow(clippy::excessive_precision)] - #[allow(deprecated)] - fn test_lamports_to_sol() { - assert_eq!(0.0, lamports_to_sol(0)); - assert_eq!(0.000000001, lamports_to_sol(1)); - assert_eq!(0.00000001, lamports_to_sol(10)); - assert_eq!(0.0000001, lamports_to_sol(100)); - assert_eq!(0.000001, lamports_to_sol(1000)); - assert_eq!(0.00001, lamports_to_sol(10000)); - assert_eq!(0.0001, lamports_to_sol(100000)); - assert_eq!(0.001, lamports_to_sol(1000000)); - assert_eq!(0.01, lamports_to_sol(10000000)); - assert_eq!(0.1, lamports_to_sol(100000000)); - assert_eq!(1., lamports_to_sol(1000000000)); - assert_eq!(4.1, lamports_to_sol(4_100_000_000)); - assert_eq!(8.2, lamports_to_sol(8_200_000_000)); - assert_eq!(8.50228288, lamports_to_sol(8_502_282_880)); - assert_eq!(18446744073.70955276489257812500, lamports_to_sol(u64::MAX)); - assert_eq!( - 18446744073.70955276489257812500, - lamports_to_sol(u64::MAX - 1023) - ); - assert_eq!( - 18446744073.70954895019531250000, - lamports_to_sol(u64::MAX - 1024) - ); - assert_eq!( - 18446744073.70954895019531250000, - lamports_to_sol(u64::MAX - 5119) - ); - assert_eq!( - 18446744073.70954513549804687500, - lamports_to_sol(u64::MAX - 5120) - ); - } - - #[test] - #[allow(clippy::excessive_precision)] - #[allow(deprecated)] - fn test_sol_to_lamports() { - assert_eq!(0, sol_to_lamports(0.0)); - assert_eq!(1, sol_to_lamports(0.000000001)); - assert_eq!(10, sol_to_lamports(0.00000001)); - assert_eq!(100, sol_to_lamports(0.0000001)); - assert_eq!(1000, sol_to_lamports(0.000001)); - assert_eq!(10000, sol_to_lamports(0.00001)); - assert_eq!(100000, sol_to_lamports(0.0001)); - assert_eq!(1000000, sol_to_lamports(0.001)); - assert_eq!(10000000, sol_to_lamports(0.01)); - assert_eq!(100000000, sol_to_lamports(0.1)); - assert_eq!(1000000000, sol_to_lamports(1.)); - assert_eq!(4_100_000_000, sol_to_lamports(4.1)); - assert_eq!(8_200_000_000, sol_to_lamports(8.2)); - assert_eq!(8_502_282_880, sol_to_lamports(8.50228288)); - assert_eq!(0, sol_to_lamports(-1.0)); - assert_eq!(0, sol_to_lamports(f64::NEG_INFINITY)); - assert_eq!(0, sol_to_lamports(f64::NAN)); - assert_eq!(u64::MAX, sol_to_lamports(f64::INFINITY)); - assert_eq!(u64::MAX, sol_to_lamports(18446744073.70955276489257812500)); - assert_eq!( - u64::MAX - 2047, - sol_to_lamports(18446744073.70954895019531250000) - ); - assert_eq!( - u64::MAX - 6143, - sol_to_lamports(18446744073.70954513549804687500) - ); - } - #[test] fn test_sol_str_to_lamports() { assert_eq!(0, sol_str_to_lamports("0.0").unwrap()); diff --git a/offchain-message/Cargo.toml b/offchain-message/Cargo.toml index 0933cc009..20aabebda 100644 --- a/offchain-message/Cargo.toml +++ b/offchain-message/Cargo.toml @@ -24,7 +24,7 @@ solana-hash = { workspace = true } solana-packet = { workspace = true } solana-pubkey = { workspace = true, optional = true } solana-sanitize = { workspace = true } -solana-sha256-hasher = { workspace = true } +solana-sha256-hasher = { workspace = true, features = ["sha2"] } solana-signature = { workspace = true } solana-signer = { workspace = true } diff --git a/package-metadata-macro/Cargo.toml b/package-metadata-macro/Cargo.toml index ba756b4b9..5ba4d2e75 100644 --- a/package-metadata-macro/Cargo.toml +++ b/package-metadata-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-package-metadata-macro" description = "Solana Package Metadata Macro" documentation = "https://docs.rs/solana-package-metadata-macro" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/precompile-error/Cargo.toml b/precompile-error/Cargo.toml index 21d5e58dc..f965530af 100644 --- a/precompile-error/Cargo.toml +++ b/precompile-error/Cargo.toml @@ -2,7 +2,8 @@ name = "solana-precompile-error" description = "Solana PrecompileError type" documentation = "https://docs.rs/solana-precompile-error" -version = "2.2.2" +version = "3.0.0" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -14,4 +15,3 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] num-traits = { workspace = true } -solana-decode-error = { workspace = true } diff --git a/precompile-error/src/lib.rs b/precompile-error/src/lib.rs index c315cb405..4acd3f5a3 100644 --- a/precompile-error/src/lib.rs +++ b/precompile-error/src/lib.rs @@ -53,7 +53,7 @@ impl num_traits::ToPrimitive for PrecompileError { } } -impl std::error::Error for PrecompileError {} +impl core::error::Error for PrecompileError {} impl fmt::Display for PrecompileError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -68,10 +68,3 @@ impl fmt::Display for PrecompileError { } } } - -#[allow(deprecated)] -impl solana_decode_error::DecodeError for PrecompileError { - fn type_of() -> &'static str { - "PrecompileError" - } -} diff --git a/precompiles/Cargo.toml b/precompiles/Cargo.toml deleted file mode 100644 index 1f8153dfe..000000000 --- a/precompiles/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "solana-precompiles" -description = "Solana precompiled programs." -documentation = "https://docs.rs/solana-precompiles" -version = "2.2.2" -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -license = { workspace = true } -edition = { workspace = true } - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] -all-features = true -rustdoc-args = ["--cfg=docsrs"] - -[features] -# Enables the "vendored" feature of openssl inside of secp256r1-program -openssl-vendored = ["solana-secp256r1-program/openssl-vendored"] - -[dependencies] -lazy_static = { workspace = true } -solana-ed25519-program = { workspace = true } -solana-feature-set = { workspace = true } -solana-message = { workspace = true } -solana-precompile-error = { workspace = true } -solana-pubkey = { workspace = true } -solana-sdk-ids = { workspace = true } -solana-secp256k1-program = { workspace = true, features = ["bincode"] } -solana-secp256r1-program = { workspace = true, default-features = false } - -[lints] -workspace = true diff --git a/precompiles/src/lib.rs b/precompiles/src/lib.rs deleted file mode 100644 index 5ae1f57ed..000000000 --- a/precompiles/src/lib.rs +++ /dev/null @@ -1,117 +0,0 @@ -#![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![deprecated(since = "2.2.2", note = "Use agave-precompiles instead")] -#![allow(deprecated)] -use { - lazy_static::lazy_static, solana_feature_set::FeatureSet, - solana_message::compiled_instruction::CompiledInstruction, - solana_precompile_error::PrecompileError, solana_pubkey::Pubkey, -}; - -/// All precompiled programs must implement the `Verify` function -pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>; - -/// Information on a precompiled program -pub struct Precompile { - /// Program id - pub program_id: Pubkey, - /// Feature to enable on, `None` indicates always enabled - pub feature: Option, - /// Verification function - pub verify_fn: Verify, -} -impl Precompile { - /// Creates a new `Precompile` - pub fn new(program_id: Pubkey, feature: Option, verify_fn: Verify) -> Self { - Precompile { - program_id, - feature, - verify_fn, - } - } - /// Check if a program id is this precompiled program - pub fn check_id(&self, program_id: &Pubkey, is_enabled: F) -> bool - where - F: Fn(&Pubkey) -> bool, - { - self.feature - .is_none_or(|ref feature_id| is_enabled(feature_id)) - && self.program_id == *program_id - } - /// Verify this precompiled program - pub fn verify( - &self, - data: &[u8], - instruction_datas: &[&[u8]], - feature_set: &FeatureSet, - ) -> std::result::Result<(), PrecompileError> { - (self.verify_fn)(data, instruction_datas, feature_set) - } -} - -lazy_static! { - /// The list of all precompiled programs - static ref PRECOMPILES: Vec = vec![ - Precompile::new( - solana_sdk_ids::secp256k1_program::id(), - None, // always enabled - solana_secp256k1_program::verify, - ), - Precompile::new( - solana_sdk_ids::ed25519_program::id(), - None, // always enabled - solana_ed25519_program::verify, - ), - Precompile::new( - solana_sdk_ids::secp256r1_program::id(), - Some(solana_feature_set::enable_secp256r1_precompile::id()), - solana_secp256r1_program::verify, - ) - ]; -} - -/// Check if a program is a precompiled program -pub fn is_precompile(program_id: &Pubkey, is_enabled: F) -> bool -where - F: Fn(&Pubkey) -> bool, -{ - PRECOMPILES - .iter() - .any(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id))) -} - -/// Find an enabled precompiled program -pub fn get_precompile(program_id: &Pubkey, is_enabled: F) -> Option<&Precompile> -where - F: Fn(&Pubkey) -> bool, -{ - PRECOMPILES - .iter() - .find(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id))) -} - -pub fn get_precompiles<'a>() -> &'a [Precompile] { - &PRECOMPILES -} - -/// Check that a program is precompiled and if so verify it -pub fn verify_if_precompile( - program_id: &Pubkey, - precompile_instruction: &CompiledInstruction, - all_instructions: &[CompiledInstruction], - feature_set: &FeatureSet, -) -> Result<(), PrecompileError> { - for precompile in PRECOMPILES.iter() { - if precompile.check_id(program_id, |feature_id| feature_set.is_active(feature_id)) { - let instruction_datas: Vec<_> = all_instructions - .iter() - .map(|instruction| instruction.data.as_ref()) - .collect(); - return precompile.verify( - &precompile_instruction.data, - &instruction_datas, - feature_set, - ); - } - } - Ok(()) -} diff --git a/program-entrypoint/Cargo.toml b/program-entrypoint/Cargo.toml index e3709d41f..90a059a5d 100644 --- a/program-entrypoint/Cargo.toml +++ b/program-entrypoint/Cargo.toml @@ -9,11 +9,14 @@ homepage = { workspace = true } license = { workspace = true } edition = { workspace = true } +rust-version = "1.81.0" + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] [dependencies] solana-account-info = { workspace = true } +solana-define-syscall = { workspace = true } solana-msg = { workspace = true } solana-program-error = { workspace = true } solana-pubkey = { workspace = true, default-features = false } diff --git a/program-entrypoint/src/lib.rs b/program-entrypoint/src/lib.rs index df4c0882d..b19307f27 100644 --- a/program-entrypoint/src/lib.rs +++ b/program-entrypoint/src/lib.rs @@ -1,8 +1,4 @@ //! The Rust-based BPF program entrypoint supported by the latest BPF loader. -//! -//! For more information see the [`bpf_loader`] module. -//! -//! [`bpf_loader`]: crate::bpf_loader extern crate alloc; use { @@ -11,10 +7,8 @@ use { solana_pubkey::Pubkey, std::{ alloc::Layout, - cell::RefCell, mem::{size_of, MaybeUninit}, ptr::null_mut, - rc::Rc, slice::{from_raw_parts, from_raw_parts_mut}, }, }; @@ -22,8 +16,12 @@ use { // entrypoint_no_alloc macro pub use { solana_account_info::AccountInfo as __AccountInfo, - solana_account_info::MAX_PERMITTED_DATA_INCREASE, solana_msg::msg as __msg, - solana_program_error::ProgramResult, solana_pubkey::Pubkey as __Pubkey, + solana_account_info::MAX_PERMITTED_DATA_INCREASE, + // Re-exporting for custom_panic + solana_define_syscall::definitions::{sol_log_ as __log, sol_panic_ as __panic}, + solana_msg::msg as __msg, + solana_program_error::ProgramResult, + solana_pubkey::Pubkey as __Pubkey, }; /// User implemented function to process an instruction @@ -223,7 +221,6 @@ macro_rules! custom_heap_default { () => { #[cfg(all(not(feature = "custom-heap"), target_os = "solana"))] #[global_allocator] - #[allow(deprecated)] //we get to use deprecated pub fields static A: $crate::BumpAllocator = $crate::BumpAllocator { start: $crate::HEAP_START_ADDRESS as usize, len: $crate::HEAP_LENGTH, @@ -234,8 +231,8 @@ macro_rules! custom_heap_default { /// Define the default global panic handler. /// /// This must be used if the [`entrypoint`] macro is not used, and no other -/// panic handler has been defined; otherwise compilation will fail with a -/// missing `custom_panic` symbol. +/// panic handler has been defined; otherwise a program will crash without an +/// explicit panic message. /// /// The default global allocator is enabled only if the calling crate has not /// disabled it using [Cargo features] as described below. It is only defined @@ -273,32 +270,36 @@ macro_rules! custom_heap_default { /// $crate::msg!("{}", info); /// } /// ``` -/// -/// The above is how Solana defines the default panic handler. #[macro_export] macro_rules! custom_panic_default { () => { #[cfg(all(not(feature = "custom-panic"), target_os = "solana"))] #[no_mangle] fn custom_panic(info: &core::panic::PanicInfo<'_>) { - // Full panic reporting - $crate::__msg!("{}", info); + if let Some(mm) = info.message().as_str() { + unsafe { + $crate::__log(mm.as_ptr(), mm.len() as u64); + } + } + + if let Some(loc) = info.location() { + unsafe { + $crate::__panic( + loc.file().as_ptr(), + loc.file().len() as u64, + loc.line() as u64, + loc.column() as u64, + ) + } + } } }; } /// The bump allocator used as the default rust heap when running programs. pub struct BumpAllocator { - #[deprecated( - since = "2.2.2", - note = "This field should not be accessed directly. It will become private in future versions" - )] - pub start: usize, - #[deprecated( - since = "2.2.2", - note = "This field should not be accessed directly. It will become private in future versions" - )] - pub len: usize, + start: usize, + len: usize, } impl BumpAllocator { @@ -327,7 +328,6 @@ impl BumpAllocator { // initialize the data there *pos_ptr = pos_ptr as usize + arena.len(); - #[allow(deprecated)] //we get to use deprecated pub fields Self { start: pos_ptr as usize, len: arena.len(), @@ -341,7 +341,6 @@ impl BumpAllocator { #[allow(clippy::arithmetic_side_effects)] unsafe impl std::alloc::GlobalAlloc for BumpAllocator { #[inline] - #[allow(deprecated)] //we get to use deprecated pub fields unsafe fn alloc(&self, layout: Layout) -> *mut u8 { let pos_ptr = self.start as *mut usize; let mut pos = *pos_ptr; @@ -410,7 +409,7 @@ unsafe fn deserialize_account_info<'a>( offset += size_of::(); #[allow(clippy::cast_ptr_alignment)] - let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64))); + let lamports = &mut *(input.add(offset) as *mut u64); offset += size_of::(); #[allow(clippy::cast_ptr_alignment)] @@ -421,18 +420,13 @@ unsafe fn deserialize_account_info<'a>( // requires that MAX_PERMITTED_DATA_LENGTH fits in a u32 *(input.add(original_data_len_offset) as *mut u32) = data_len as u32; - let data = Rc::new(RefCell::new({ - from_raw_parts_mut(input.add(offset), data_len) - })); - offset += data_len + MAX_PERMITTED_DATA_INCREASE; + let data = from_raw_parts_mut(input.add(offset), data_len); + // rent epoch is not deserialized, so skip it + offset += data_len + MAX_PERMITTED_DATA_INCREASE + size_of::(); offset += (offset as *const u8).align_offset(BPF_ALIGN_OF_U128); // padding - #[allow(clippy::cast_ptr_alignment)] - let rent_epoch = *(input.add(offset) as *const u64); - offset += size_of::(); - ( - AccountInfo { + AccountInfo::new( key, is_signer, is_writable, @@ -440,8 +434,7 @@ unsafe fn deserialize_account_info<'a>( data, owner, executable, - rent_epoch, - }, + ), offset, ) } diff --git a/program-error/Cargo.toml b/program-error/Cargo.toml index 2d2103b7e..3691de3b4 100644 --- a/program-error/Cargo.toml +++ b/program-error/Cargo.toml @@ -2,7 +2,8 @@ name = "solana-program-error" description = "Solana ProgramError type and related definitions." documentation = "https://docs.rs/solana-program-error" -version = "2.2.2" +version = "3.0.0" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -20,12 +21,8 @@ serde = ["dep:serde", "dep:serde_derive"] [dependencies] borsh = { workspace = true, optional = true } -num-traits = { workspace = true } serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } -solana-decode-error = { workspace = true } -solana-instruction = { workspace = true, default-features = false, features = [ - "std", -] } -solana-msg = { workspace = true } -solana-pubkey = { workspace = true, default-features = false } + +[dev-dependencies] +num_enum = { workspace = true } diff --git a/program-error/src/lib.rs b/program-error/src/lib.rs index f77043e41..8e3bdabbc 100644 --- a/program-error/src/lib.rs +++ b/program-error/src/lib.rs @@ -2,30 +2,54 @@ #![allow(clippy::arithmetic_side_effects)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![no_std] #[cfg(feature = "borsh")] use borsh::io::Error as BorshIoError; +use core::{convert::TryFrom, fmt}; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; -use { - core::fmt, - num_traits::FromPrimitive, - solana_instruction::error::{ - InstructionError, ACCOUNT_ALREADY_INITIALIZED, ACCOUNT_BORROW_FAILED, - ACCOUNT_DATA_TOO_SMALL, ACCOUNT_NOT_RENT_EXEMPT, ARITHMETIC_OVERFLOW, BORSH_IO_ERROR, - BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS, CUSTOM_ZERO, ILLEGAL_OWNER, IMMUTABLE, - INCORRECT_AUTHORITY, INCORRECT_PROGRAM_ID, INSUFFICIENT_FUNDS, INVALID_ACCOUNT_DATA, - INVALID_ACCOUNT_DATA_REALLOC, INVALID_ACCOUNT_OWNER, INVALID_ARGUMENT, - INVALID_INSTRUCTION_DATA, INVALID_SEEDS, MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED, - MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED, MAX_SEED_LENGTH_EXCEEDED, - MISSING_REQUIRED_SIGNATURES, NOT_ENOUGH_ACCOUNT_KEYS, UNINITIALIZED_ACCOUNT, - UNSUPPORTED_SYSVAR, - }, - solana_msg::msg, - solana_pubkey::PubkeyError, - std::convert::TryFrom, -}; -pub type ProgramResult = std::result::Result<(), ProgramError>; +pub type ProgramResult = core::result::Result<(), ProgramError>; + +/// Builtin return values occupy the upper 32 bits +pub const BUILTIN_BIT_SHIFT: usize = 32; +macro_rules! to_builtin { + ($error:expr) => { + ($error as u64) << BUILTIN_BIT_SHIFT + }; +} + +pub const CUSTOM_ZERO: u64 = to_builtin!(1); +pub const INVALID_ARGUMENT: u64 = to_builtin!(2); +pub const INVALID_INSTRUCTION_DATA: u64 = to_builtin!(3); +pub const INVALID_ACCOUNT_DATA: u64 = to_builtin!(4); +pub const ACCOUNT_DATA_TOO_SMALL: u64 = to_builtin!(5); +pub const INSUFFICIENT_FUNDS: u64 = to_builtin!(6); +pub const INCORRECT_PROGRAM_ID: u64 = to_builtin!(7); +pub const MISSING_REQUIRED_SIGNATURES: u64 = to_builtin!(8); +pub const ACCOUNT_ALREADY_INITIALIZED: u64 = to_builtin!(9); +pub const UNINITIALIZED_ACCOUNT: u64 = to_builtin!(10); +pub const NOT_ENOUGH_ACCOUNT_KEYS: u64 = to_builtin!(11); +pub const ACCOUNT_BORROW_FAILED: u64 = to_builtin!(12); +pub const MAX_SEED_LENGTH_EXCEEDED: u64 = to_builtin!(13); +pub const INVALID_SEEDS: u64 = to_builtin!(14); +pub const BORSH_IO_ERROR: u64 = to_builtin!(15); +pub const ACCOUNT_NOT_RENT_EXEMPT: u64 = to_builtin!(16); +pub const UNSUPPORTED_SYSVAR: u64 = to_builtin!(17); +pub const ILLEGAL_OWNER: u64 = to_builtin!(18); +pub const MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED: u64 = to_builtin!(19); +pub const INVALID_ACCOUNT_DATA_REALLOC: u64 = to_builtin!(20); +pub const MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED: u64 = to_builtin!(21); +pub const BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS: u64 = to_builtin!(22); +pub const INVALID_ACCOUNT_OWNER: u64 = to_builtin!(23); +pub const ARITHMETIC_OVERFLOW: u64 = to_builtin!(24); +pub const IMMUTABLE: u64 = to_builtin!(25); +pub const INCORRECT_AUTHORITY: u64 = to_builtin!(26); +// Warning: Any new error codes added here must also be: +// - Added to the below conversions +// - Added as an equivalent to ProgramError and InstructionError +// - Be featurized in the BPF loader to return `InstructionError::InvalidError` +// until the feature is activated /// Reasons the program may fail #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -48,7 +72,7 @@ pub enum ProgramError { AccountBorrowFailed, MaxSeedLengthExceeded, InvalidSeeds, - BorshIoError(String), + BorshIoError, AccountNotRentExempt, UnsupportedSysvar, IllegalOwner, @@ -62,7 +86,7 @@ pub enum ProgramError { IncorrectAuthority, } -impl std::error::Error for ProgramError {} +impl core::error::Error for ProgramError {} impl fmt::Display for ProgramError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -94,7 +118,7 @@ impl fmt::Display for ProgramError { => f.write_str("Length of the seed is too long for address generation"), ProgramError::InvalidSeeds => f.write_str("Provided seeds do not result in a valid address"), - ProgramError::BorshIoError(s) => write!(f, "IO Error: {s}"), + ProgramError::BorshIoError => f.write_str("IO Error"), ProgramError::AccountNotRentExempt => f.write_str("An account does not have enough lamports to be rent-exempt"), ProgramError::UnsupportedSysvar @@ -121,90 +145,54 @@ impl fmt::Display for ProgramError { } } -#[deprecated( - since = "2.2.2", - note = "Use `ToStr` instead with `solana_msg::msg!` or any other logging" -)] -#[allow(deprecated)] -pub trait PrintProgramError { - fn print(&self) - where - E: 'static - + std::error::Error - + solana_decode_error::DecodeError - + PrintProgramError - + FromPrimitive; -} - -#[allow(deprecated)] -impl PrintProgramError for ProgramError { - fn print(&self) - where - E: 'static - + std::error::Error - + solana_decode_error::DecodeError - + PrintProgramError - + FromPrimitive, - { - match self { - Self::Custom(error) => { - if let Some(custom_error) = E::decode_custom_error_to_enum(*error) { - custom_error.print::(); - } else { - msg!("Error: Unknown"); - } - } - Self::InvalidArgument => msg!("Error: InvalidArgument"), - Self::InvalidInstructionData => msg!("Error: InvalidInstructionData"), - Self::InvalidAccountData => msg!("Error: InvalidAccountData"), - Self::AccountDataTooSmall => msg!("Error: AccountDataTooSmall"), - Self::InsufficientFunds => msg!("Error: InsufficientFunds"), - Self::IncorrectProgramId => msg!("Error: IncorrectProgramId"), - Self::MissingRequiredSignature => msg!("Error: MissingRequiredSignature"), - Self::AccountAlreadyInitialized => msg!("Error: AccountAlreadyInitialized"), - Self::UninitializedAccount => msg!("Error: UninitializedAccount"), - Self::NotEnoughAccountKeys => msg!("Error: NotEnoughAccountKeys"), - Self::AccountBorrowFailed => msg!("Error: AccountBorrowFailed"), - Self::MaxSeedLengthExceeded => msg!("Error: MaxSeedLengthExceeded"), - Self::InvalidSeeds => msg!("Error: InvalidSeeds"), - Self::BorshIoError(_) => msg!("Error: BorshIoError"), - Self::AccountNotRentExempt => msg!("Error: AccountNotRentExempt"), - Self::UnsupportedSysvar => msg!("Error: UnsupportedSysvar"), - Self::IllegalOwner => msg!("Error: IllegalOwner"), - Self::MaxAccountsDataAllocationsExceeded => { - msg!("Error: MaxAccountsDataAllocationsExceeded") - } - Self::InvalidRealloc => msg!("Error: InvalidRealloc"), - Self::MaxInstructionTraceLengthExceeded => { - msg!("Error: MaxInstructionTraceLengthExceeded") - } - Self::BuiltinProgramsMustConsumeComputeUnits => { - msg!("Error: BuiltinProgramsMustConsumeComputeUnits") - } - Self::InvalidAccountOwner => msg!("Error: InvalidAccountOwner"), - Self::ArithmeticOverflow => msg!("Error: ArithmeticOverflow"), - Self::Immutable => msg!("Error: Immutable"), - Self::IncorrectAuthority => msg!("Error: IncorrectAuthority"), - } - } -} - -/// A trait for converting a program error to a `&str`. +/// A trait for converting a program's specific error type to a `&str`. +/// +/// Can be used with `ProgramError::to_str::()` to get an error string +/// belonging to a specific program's error if the variant is +/// `ProgramError::Custom(...)`, or generic strings from the contained +/// `ProgramError` for all other variants. +/// +/// The `ProgramError::to_str::()` function also requires implementing +/// `TryFrom` on an error type, which can be done easily using +/// `num_enum::TryFromPrimitive`. pub trait ToStr { - fn to_str(&self) -> &'static str - where - E: 'static + ToStr + TryFrom; + fn to_str(&self) -> &'static str; } -impl ToStr for ProgramError { - fn to_str(&self) -> &'static str +impl ProgramError { + /// Get an appropriate error string given a program error and an expected + /// error type, if the error implements `TryFrom` and `ToStr`. + /// + /// # Example + /// + /// ``` + /// #[derive(num_enum::TryFromPrimitive)] + /// #[repr(u32)] + /// enum MyError { + /// A, + /// B, + /// } + /// + /// impl solana_program_error::ToStr for MyError { + /// fn to_str(&self) -> &'static str { + /// match self { + /// MyError::A => "Message for A", + /// MyError::B => "Some other message for B", + /// } + /// } + /// } + /// + /// let program_error = solana_program_error::ProgramError::Custom(1); + /// assert_eq!("Some other message for B", program_error.to_str::()); + /// ``` + pub fn to_str(&self) -> &'static str where E: 'static + ToStr + TryFrom, { match self { Self::Custom(error) => { if let Ok(custom_error) = E::try_from(*error) { - custom_error.to_str::() + custom_error.to_str() } else { "Error: Unknown" } @@ -222,7 +210,7 @@ impl ToStr for ProgramError { Self::AccountBorrowFailed => "Error: AccountBorrowFailed", Self::MaxSeedLengthExceeded => "Error: MaxSeedLengthExceeded", Self::InvalidSeeds => "Error: InvalidSeeds", - Self::BorshIoError(_) => "Error: BorshIoError", + Self::BorshIoError => "Error: BorshIoError", Self::AccountNotRentExempt => "Error: AccountNotRentExempt", Self::UnsupportedSysvar => "Error: UnsupportedSysvar", Self::IllegalOwner => "Error: IllegalOwner", @@ -256,7 +244,7 @@ impl From for u64 { ProgramError::AccountBorrowFailed => ACCOUNT_BORROW_FAILED, ProgramError::MaxSeedLengthExceeded => MAX_SEED_LENGTH_EXCEEDED, ProgramError::InvalidSeeds => INVALID_SEEDS, - ProgramError::BorshIoError(_) => BORSH_IO_ERROR, + ProgramError::BorshIoError => BORSH_IO_ERROR, ProgramError::AccountNotRentExempt => ACCOUNT_NOT_RENT_EXEMPT, ProgramError::UnsupportedSysvar => UNSUPPORTED_SYSVAR, ProgramError::IllegalOwner => ILLEGAL_OWNER, @@ -302,7 +290,7 @@ impl From for ProgramError { ACCOUNT_BORROW_FAILED => Self::AccountBorrowFailed, MAX_SEED_LENGTH_EXCEEDED => Self::MaxSeedLengthExceeded, INVALID_SEEDS => Self::InvalidSeeds, - BORSH_IO_ERROR => Self::BorshIoError("Unknown".to_string()), + BORSH_IO_ERROR => Self::BorshIoError, ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt, UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar, ILLEGAL_OWNER => Self::IllegalOwner, @@ -321,61 +309,9 @@ impl From for ProgramError { } } -impl TryFrom for ProgramError { - type Error = InstructionError; - - fn try_from(error: InstructionError) -> Result { - match error { - Self::Error::Custom(err) => Ok(Self::Custom(err)), - Self::Error::InvalidArgument => Ok(Self::InvalidArgument), - Self::Error::InvalidInstructionData => Ok(Self::InvalidInstructionData), - Self::Error::InvalidAccountData => Ok(Self::InvalidAccountData), - Self::Error::AccountDataTooSmall => Ok(Self::AccountDataTooSmall), - Self::Error::InsufficientFunds => Ok(Self::InsufficientFunds), - Self::Error::IncorrectProgramId => Ok(Self::IncorrectProgramId), - Self::Error::MissingRequiredSignature => Ok(Self::MissingRequiredSignature), - Self::Error::AccountAlreadyInitialized => Ok(Self::AccountAlreadyInitialized), - Self::Error::UninitializedAccount => Ok(Self::UninitializedAccount), - Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys), - Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed), - Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded), - Self::Error::InvalidSeeds => Ok(Self::InvalidSeeds), - Self::Error::BorshIoError(err) => Ok(Self::BorshIoError(err)), - Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt), - Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar), - Self::Error::IllegalOwner => Ok(Self::IllegalOwner), - Self::Error::MaxAccountsDataAllocationsExceeded => { - Ok(Self::MaxAccountsDataAllocationsExceeded) - } - Self::Error::InvalidRealloc => Ok(Self::InvalidRealloc), - Self::Error::MaxInstructionTraceLengthExceeded => { - Ok(Self::MaxInstructionTraceLengthExceeded) - } - Self::Error::BuiltinProgramsMustConsumeComputeUnits => { - Ok(Self::BuiltinProgramsMustConsumeComputeUnits) - } - Self::Error::InvalidAccountOwner => Ok(Self::InvalidAccountOwner), - Self::Error::ArithmeticOverflow => Ok(Self::ArithmeticOverflow), - Self::Error::Immutable => Ok(Self::Immutable), - Self::Error::IncorrectAuthority => Ok(Self::IncorrectAuthority), - _ => Err(error), - } - } -} - -impl From for ProgramError { - fn from(error: PubkeyError) -> Self { - match error { - PubkeyError::MaxSeedLengthExceeded => Self::MaxSeedLengthExceeded, - PubkeyError::InvalidSeeds => Self::InvalidSeeds, - PubkeyError::IllegalOwner => Self::IllegalOwner, - } - } -} - #[cfg(feature = "borsh")] impl From for ProgramError { - fn from(error: BorshIoError) -> Self { - Self::BorshIoError(format!("{error}")) + fn from(_error: BorshIoError) -> Self { + Self::BorshIoError } } diff --git a/program-memory/Cargo.toml b/program-memory/Cargo.toml index 3a37e1143..29b8e11fd 100644 --- a/program-memory/Cargo.toml +++ b/program-memory/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-program-memory" description = "Basic low-level memory operations for Solana." documentation = "https://docs.rs/solana-program-memory" -version = "2.3.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/program-memory/src/lib.rs b/program-memory/src/lib.rs index 6077d480c..c1f6a39da 100644 --- a/program-memory/src/lib.rs +++ b/program-memory/src/lib.rs @@ -1,8 +1,12 @@ +#![no_std] + //! Basic low-level memory operations. //! //! Within the SBF environment, these are implemented as syscalls and executed by //! the runtime in native code. +use core::mem::MaybeUninit; + #[cfg(target_os = "solana")] pub mod syscalls { pub use solana_define_syscall::definitions::{ @@ -33,11 +37,11 @@ pub mod stubs { is_nonoverlapping(src as usize, n, dst as usize, n), "memcpy does not support overlapping regions" ); - std::ptr::copy_nonoverlapping(src, dst, n); + core::ptr::copy_nonoverlapping(src, dst, n); } /// # Safety pub unsafe fn sol_memmove(dst: *mut u8, src: *const u8, n: usize) { - std::ptr::copy(src, dst, n); + core::ptr::copy(src, dst, n); } /// # Safety pub unsafe fn sol_memcmp(s1: *const u8, s2: *const u8, n: usize, result: *mut i32) { @@ -55,7 +59,7 @@ pub mod stubs { } /// # Safety pub unsafe fn sol_memset(s: *mut u8, c: u8, n: usize) { - let s = std::slice::from_raw_parts_mut(s, n); + let s = core::slice::from_raw_parts_mut(s, n); for val in s.iter_mut().take(n) { *val = c; } @@ -82,8 +86,6 @@ pub mod stubs { /// /// # Safety /// -/// __This function is incorrectly missing an `unsafe` declaration.__ -/// /// This function does not verify that `n` is less than or equal to the /// lengths of the `dst` and `src` slices passed to it — it will copy /// bytes to and from beyond the slices. @@ -91,16 +93,12 @@ pub mod stubs { /// Specifying an `n` greater than either the length of `dst` or `src` will /// likely introduce undefined behavior. #[inline] -pub fn sol_memcpy(dst: &mut [u8], src: &[u8], n: usize) { +pub unsafe fn sol_memcpy(dst: &mut [u8], src: &[u8], n: usize) { #[cfg(target_os = "solana")] - unsafe { - syscalls::sol_memcpy_(dst.as_mut_ptr(), src.as_ptr(), n as u64); - } + syscalls::sol_memcpy_(dst.as_mut_ptr(), src.as_ptr(), n as u64); #[cfg(not(target_os = "solana"))] - unsafe { - stubs::sol_memcpy(dst.as_mut_ptr(), src.as_ptr(), n); - } + stubs::sol_memcpy(dst.as_mut_ptr(), src.as_ptr(), n); } /// Like C `memmove`. @@ -121,7 +119,7 @@ pub fn sol_memcpy(dst: &mut [u8], src: &[u8], n: usize) { /// /// The same safety rules apply as in [`ptr::copy`]. /// -/// [`ptr::copy`]: https://doc.rust-lang.org/std/ptr/fn.copy.html +/// [`ptr::copy`]: https://doc.rust-lang.org/core/ptr/fn.copy.html #[inline] pub unsafe fn sol_memmove(dst: *mut u8, src: *const u8, n: usize) { #[cfg(target_os = "solana")] @@ -147,8 +145,6 @@ pub unsafe fn sol_memmove(dst: *mut u8, src: *const u8, n: usize) { /// /// # Safety /// -/// __This function is incorrectly missing an `unsafe` declaration.__ -/// /// It does not verify that `n` is less than or equal to the lengths of the /// `dst` and `src` slices passed to it — it will read bytes beyond the /// slices. @@ -156,20 +152,16 @@ pub unsafe fn sol_memmove(dst: *mut u8, src: *const u8, n: usize) { /// Specifying an `n` greater than either the length of `dst` or `src` will /// likely introduce undefined behavior. #[inline] -pub fn sol_memcmp(s1: &[u8], s2: &[u8], n: usize) -> i32 { - let mut result = 0; +pub unsafe fn sol_memcmp(s1: &[u8], s2: &[u8], n: usize) -> i32 { + let mut result: MaybeUninit = MaybeUninit::uninit(); #[cfg(target_os = "solana")] - unsafe { - syscalls::sol_memcmp_(s1.as_ptr(), s2.as_ptr(), n as u64, &mut result as *mut i32); - } + syscalls::sol_memcmp_(s1.as_ptr(), s2.as_ptr(), n as u64, result.as_mut_ptr()); #[cfg(not(target_os = "solana"))] - unsafe { - stubs::sol_memcmp(s1.as_ptr(), s2.as_ptr(), n, &mut result as *mut i32); - } + stubs::sol_memcmp(s1.as_ptr(), s2.as_ptr(), n, result.as_mut_ptr()); - result + result.assume_init() } /// Like C `memset`. @@ -188,8 +180,6 @@ pub fn sol_memcmp(s1: &[u8], s2: &[u8], n: usize) -> i32 { /// /// # Safety /// -/// __This function is incorrectly missing an `unsafe` declaration.__ -/// /// This function does not verify that `n` is less than or equal to the length /// of the `s` slice passed to it — it will write bytes beyond the /// slice. @@ -197,16 +187,12 @@ pub fn sol_memcmp(s1: &[u8], s2: &[u8], n: usize) -> i32 { /// Specifying an `n` greater than the length of `s` will likely introduce /// undefined behavior. #[inline] -pub fn sol_memset(s: &mut [u8], c: u8, n: usize) { +pub unsafe fn sol_memset(s: &mut [u8], c: u8, n: usize) { #[cfg(target_os = "solana")] - unsafe { - syscalls::sol_memset_(s.as_mut_ptr(), c, n as u64); - } + syscalls::sol_memset_(s.as_mut_ptr(), c, n as u64); #[cfg(not(target_os = "solana"))] - unsafe { - stubs::sol_memset(s.as_mut_ptr(), c, n); - } + stubs::sol_memset(s.as_mut_ptr(), c, n); } #[cfg(test)] diff --git a/program-option/Cargo.toml b/program-option/Cargo.toml index 049d384ed..6bfba39fa 100644 --- a/program-option/Cargo.toml +++ b/program-option/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-program-option" description = "A C representation of Rust's Option, used in Solana programs." documentation = "https://docs.rs/solana-program-option" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/program/Cargo.toml b/program/Cargo.toml index 3a1136ade..0d5cc4c99 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -9,7 +9,7 @@ repository = { workspace = true } homepage = { workspace = true } license = { workspace = true } edition = { workspace = true } -rust-version = "1.79.0" # solana platform-tools rust version +rust-version = "1.81.0" # solana platform-tools rust version include = ["src/**/*", "README.md"] [package.metadata.docs.rs] @@ -18,21 +18,22 @@ all-features = true rustdoc-args = ["--cfg=docsrs"] [lib] -crate-type = ["cdylib", "rlib"] +crate-type = ["rlib"] [features] default = ["borsh"] borsh = [ - "dep:borsh", - "dep:borsh0-10", "dep:solana-borsh", "solana-hash/borsh", "solana-instruction/borsh", "solana-program-error/borsh", "solana-pubkey/borsh", - "solana-stake-interface/borsh", ] -dev-context-only-utils = ["solana-instructions-sysvar/dev-context-only-utils"] +dev-context-only-utils = [ + "solana-instructions-sysvar/dev-context-only-utils", + "dep:solana-system-interface", + "solana-system-interface/bincode", +] frozen-abi = [ "dep:solana-frozen-abi", "dep:solana-frozen-abi-macro", @@ -41,42 +42,23 @@ frozen-abi = [ "solana-fee-calculator/frozen-abi", "solana-hash/frozen-abi", "solana-instruction/frozen-abi", - "solana-message/frozen-abi", "solana-pubkey/frozen-abi", "solana-rent/frozen-abi", "solana-short-vec/frozen-abi", - "solana-stake-interface/frozen-abi", "solana-sysvar/frozen-abi", ] [dependencies] -bincode = { workspace = true } -blake3 = { workspace = true, features = ["traits-preview"] } -borsh = { workspace = true, optional = true } -borsh0-10 = { workspace = true, optional = true } -bs58 = { workspace = true, features = ["alloc"] } -bytemuck = { workspace = true } -lazy_static = { workspace = true } -log = { workspace = true } memoffset = { workspace = true } -num-derive = { workspace = true } -num-traits = { workspace = true, features = ["i128"] } -serde = { workspace = true } -serde_bytes = { workspace = true } -serde_derive = { workspace = true } solana-account-info = { workspace = true, features = ["bincode"] } -solana-address-lookup-table-interface = { workspace = true, features = ["bincode", "bytemuck"] } -solana-atomic-u64 = { workspace = true } solana-big-mod-exp = { workspace = true } -solana-bincode = { workspace = true } solana-blake3-hasher = { workspace = true, features = ["blake3"] } solana-borsh = { workspace = true, optional = true } solana-clock = { workspace = true, features = ["serde", "sysvar"] } solana-cpi = { workspace = true } -solana-decode-error = { workspace = true } solana-epoch-rewards = { workspace = true, features = ["serde", "sysvar"] } solana-epoch-schedule = { workspace = true, features = ["serde", "sysvar"] } -solana-feature-gate-interface = { workspace = true, features = ["bincode"] } +solana-epoch-stake = { workspace = true } solana-fee-calculator = { workspace = true, features = ["serde"] } solana-frozen-abi = { workspace = true, optional = true, features = ["frozen-abi"] } solana-frozen-abi-macro = { workspace = true, optional = true, features = ["frozen-abi"] } @@ -91,16 +73,12 @@ solana-instruction = { workspace = true, default-features = false, features = [ "std", "syscalls", ] } +solana-instruction-error = { workspace = true, features = ["num-traits"] } solana-instructions-sysvar = { workspace = true } solana-keccak-hasher = { workspace = true, features = ["sha3"] } solana-last-restart-slot = { workspace = true, features = ["serde", "sysvar"] } -solana-loader-v2-interface = { workspace = true, features = ["bincode"] } -solana-loader-v3-interface = { workspace = true, features = ["bincode"] } -solana-loader-v4-interface = { workspace = true, features = ["bincode"] } -solana-message = { workspace = true, features = ["bincode", "blake3"] } solana-msg = { workspace = true } solana-native-token = { workspace = true } -solana-nonce = { workspace = true, features = ["serde"] } solana-program-entrypoint = { workspace = true } solana-program-error = { workspace = true, features = ["serde"] } solana-program-memory = { workspace = true } @@ -108,9 +86,7 @@ solana-program-option = { workspace = true } solana-program-pack = { workspace = true } solana-pubkey = { workspace = true, features = ["bytemuck", "curve25519", "serde", "std"] } solana-rent = { workspace = true, features = ["serde", "sysvar"] } -solana-sanitize = { workspace = true } solana-sdk-ids = { workspace = true } -solana-sdk-macro = { workspace = true } solana-secp256k1-recover = { workspace = true } solana-serde-varint = { workspace = true } solana-serialize-utils = { workspace = true } @@ -119,45 +95,19 @@ solana-short-vec = { workspace = true } solana-slot-hashes = { workspace = true, features = ["serde", "sysvar"] } solana-slot-history = { workspace = true, features = ["serde", "sysvar"] } solana-stable-layout = { workspace = true } -solana-stake-interface = { workspace = true, features = ["bincode"] } -solana-system-interface = { workspace = true, features = ["bincode"] } +solana-system-interface = { optional = true, workspace = true, features = ["bincode"] } solana-sysvar = { workspace = true, features = ["bincode", "bytemuck"] } solana-sysvar-id = { workspace = true } -solana-vote-interface = { workspace = true, features = ["bincode"] } -thiserror = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] -num-bigint = { workspace = true } -rand = { workspace = true } solana-example-mocks = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -console_error_panic_hook = { workspace = true } -console_log = { workspace = true } -getrandom = { workspace = true, features = ["js", "wasm-bindgen"] } -wasm-bindgen = { workspace = true } - -# This is currently needed to build on-chain programs reliably. -# Borsh 0.10 may pull in hashbrown 0.13, which uses ahash 0.8, which uses -# getrandom 0.2 underneath. This explicit dependency allows for no-std if cargo -# upgrades Borsh's dependency to hashbrown 0.13. -# Remove this once borsh 0.11 or 1.0 is released, which correctly declares the -# hashbrown dependency as optional. [target.'cfg(target_os = "solana")'.dependencies] -getrandom = { workspace = true, features = ["custom"] } solana-define-syscall = { workspace = true } [dev-dependencies] -array-bytes = { workspace = true } -assert_matches = { workspace = true } -itertools = { workspace = true } -serde_json = { workspace = true } solana-pubkey = { workspace = true, features = ["dev-context-only-utils"] } solana-sysvar = { workspace = true, features = ["dev-context-only-utils"] } -[target.'cfg(not(target_os = "solana"))'.dev-dependencies] -arbitrary = { workspace = true, features = ["derive"] } -solana-logger = { workspace = true } - [lints] workspace = true diff --git a/program/src/address_lookup_table.rs b/program/src/address_lookup_table.rs deleted file mode 100644 index 4c0ed3b85..000000000 --- a/program/src/address_lookup_table.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![deprecated( - since = "2.3.0", - note = "Use solana-address-lookup-table-interface and solana-message instead" -)] - -pub use { - solana_address_lookup_table_interface::{error, instruction, program, state}, - solana_message::AddressLookupTableAccount, -}; diff --git a/program/src/bpf_loader.rs b/program/src/bpf_loader.rs index c8cf69fe1..8d3177b16 100644 --- a/program/src/bpf_loader.rs +++ b/program/src/bpf_loader.rs @@ -19,5 +19,5 @@ //! //! [`bpf_loader_deprecated`]: crate::bpf_loader_deprecated //! [`entrypoint_deprecated`]: mod@crate::entrypoint_deprecated -//! [ubpfl]: crate::bpf_loader_upgradeable +//! [ubpfl]: https://docs.rs/solana-loader-v3-interface/latest/solana_loader_v3_interface/index.html pub use solana_sdk_ids::bpf_loader::{check_id, id, ID}; diff --git a/program/src/bpf_loader_upgradeable.rs b/program/src/bpf_loader_upgradeable.rs deleted file mode 100644 index b6e6339b7..000000000 --- a/program/src/bpf_loader_upgradeable.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![deprecated(since = "2.3.0", note = "Use solana-loader-v3-interface instead")] - -#[allow(deprecated)] -pub use solana_loader_v3_interface::{ - get_program_data_address, - instruction::{ - close, close_any, create_buffer, deploy_with_max_program_len, extend_program, - is_close_instruction, is_set_authority_checked_instruction, is_set_authority_instruction, - is_upgrade_instruction, set_buffer_authority, set_buffer_authority_checked, - set_upgrade_authority, set_upgrade_authority_checked, upgrade, write, - }, - state::UpgradeableLoaderState, -}; -pub use solana_sdk_ids::bpf_loader_upgradeable::{check_id, id, ID}; diff --git a/program/src/entrypoint_deprecated.rs b/program/src/entrypoint_deprecated.rs index ecf3a83d0..60fea304c 100644 --- a/program/src/entrypoint_deprecated.rs +++ b/program/src/entrypoint_deprecated.rs @@ -14,9 +14,7 @@ use { crate::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}, alloc::vec::Vec, std::{ - cell::RefCell, mem::size_of, - rc::Rc, result::Result as ResultGeneric, slice::{from_raw_parts, from_raw_parts_mut}, }, @@ -89,16 +87,14 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec(); #[allow(clippy::cast_ptr_alignment)] - let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64))); + let lamports = &mut *(input.add(offset) as *mut u64); offset += size_of::(); #[allow(clippy::cast_ptr_alignment)] let data_len = *(input.add(offset) as *const u64) as usize; offset += size_of::(); - let data = Rc::new(RefCell::new({ - from_raw_parts_mut(input.add(offset), data_len) - })); + let data = from_raw_parts_mut(input.add(offset), data_len); offset += data_len; let owner: &Pubkey = &*(input.add(offset) as *const Pubkey); @@ -108,11 +104,10 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec(); - #[allow(clippy::cast_ptr_alignment)] - let rent_epoch = *(input.add(offset) as *const u64); + // rent epoch is skipped offset += size_of::(); - accounts.push(AccountInfo { + accounts.push(AccountInfo::new( key, is_signer, is_writable, @@ -120,8 +115,7 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec = { - let mut sdk_ids = vec![ - ed25519_program::id(), - secp256k1_program::id(), - system_program::id(), - sysvar::id(), - bpf_loader::id(), - bpf_loader_upgradeable::id(), - incinerator::id(), - config::program::id(), - vote::program::id(), - feature::id(), - bpf_loader_deprecated::id(), - address_lookup_table::program::id(), - loader_v4::id(), - stake::program::id(), - #[allow(deprecated)] - stake::config::id(), - ]; - sdk_ids.extend(sysvar::ALL_IDS.iter()); - sdk_ids - }; - } -} - -#[deprecated(since = "2.3.0", note = "Use `num_traits::FromPrimitive` instead")] -pub mod decode_error { - pub use solana_decode_error::*; -} pub use solana_pubkey::{declare_deprecated_id, declare_id, pubkey}; #[deprecated(since = "2.1.0", note = "Use `solana-sysvar-id` crate instead")] pub use solana_sysvar_id::{declare_deprecated_sysvar_id, declare_sysvar_id}; diff --git a/program/src/loader_v4.rs b/program/src/loader_v4.rs deleted file mode 100644 index c584b66f8..000000000 --- a/program/src/loader_v4.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![deprecated(since = "2.3.0", note = "Use solana-loader-v4-interface instead")] -pub use { - solana_loader_v4_interface::{ - instruction::{ - create_buffer, deploy, deploy_from_source, finalize, is_deploy_instruction, - is_finalize_instruction, is_retract_instruction, is_set_program_length_instruction, - is_transfer_authority_instruction, is_write_instruction, retract, - set_program_length as truncate, transfer_authority, write, - }, - state::{LoaderV4State, LoaderV4Status}, - DEPLOYMENT_COOLDOWN_IN_SLOTS, - }, - solana_sdk_ids::loader_v4::{check_id, id, ID}, -}; diff --git a/program/src/nonce.rs b/program/src/nonce.rs deleted file mode 100644 index 010dc94f8..000000000 --- a/program/src/nonce.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![deprecated(since = "2.3.0", note = "Use solana_nonce instead")] - -pub use solana_nonce::{state::State, NONCED_TX_MARKER_IX_INDEX}; -pub mod state { - pub use solana_nonce::{ - state::{Data, DurableNonce, State}, - versions::{AuthorizeNonceError, Versions}, - }; -} diff --git a/program/src/program.rs b/program/src/program.rs index 122f88ab4..6816a805f 100644 --- a/program/src/program.rs +++ b/program/src/program.rs @@ -10,14 +10,11 @@ //! [`invoke_signed`]: invoke_signed //! [cpi]: https://solana.com/docs/core/cpi -pub use solana_cpi::MAX_RETURN_DATA; -use { - crate::{ - account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, - pubkey::Pubkey, stable_layout::stable_instruction::StableInstruction, - }, - solana_clock::Epoch, +use crate::{ + account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, pubkey::Pubkey, + stable_layout::stable_instruction::StableInstruction, }; +pub use solana_cpi::MAX_RETURN_DATA; /// Like [`solana_cpi::invoke`], but with support /// for overwriting the `sol_invoke_signed` syscall stub. @@ -136,9 +133,7 @@ pub fn check_type_assumptions() { crate::instruction::AccountMeta, memoffset::offset_of, std::{ - cell::RefCell, mem::{align_of, size_of}, - rc::Rc, str::FromStr, }, }; @@ -208,80 +203,7 @@ pub fn check_type_assumptions() { } } - // Enforce AccountInfo layout - { - let key = Pubkey::from_str("6o8R9NsUxNskF1MfWM1f265y4w86JYbEwqCmTacdLkHp").unwrap(); - let mut lamports = 31; - let mut data = vec![1, 2, 3, 4, 5]; - let owner = Pubkey::from_str("2tjK4XyNU54XdN9jokx46QzLybbLVGwQQvTfhcuBXAjR").unwrap(); - let account_info = AccountInfo { - key: &key, - is_signer: true, - is_writable: false, - lamports: Rc::new(RefCell::new(&mut lamports)), - data: Rc::new(RefCell::new(&mut data)), - owner: &owner, - executable: true, - rent_epoch: 42, - }; - let account_info_addr = &account_info as *const _ as u64; - - // key - assert_eq!(offset_of!(AccountInfo, key), 0); - let key_ptr = (account_info_addr) as *const &Pubkey; - unsafe { - assert_eq!(**key_ptr, key); - } - - // lamports - assert_eq!(offset_of!(AccountInfo, lamports), 8); - let lamports_ptr = (account_info_addr + 8) as *const Rc>; - unsafe { - assert_eq!(**(*lamports_ptr).as_ptr(), 31); - } - - // data - assert_eq!(offset_of!(AccountInfo, data), 16); - let data_ptr = (account_info_addr + 16) as *const Rc>; - unsafe { - assert_eq!((*(*data_ptr).as_ptr())[..], data[..]); - } - - // owner - assert_eq!(offset_of!(AccountInfo, owner), 24); - let owner_ptr = (account_info_addr + 24) as *const &Pubkey; - unsafe { - assert_eq!(**owner_ptr, owner); - } - - // rent_epoch - assert_eq!(offset_of!(AccountInfo, rent_epoch), 32); - let renbt_epoch_ptr = (account_info_addr + 32) as *const Epoch; - unsafe { - assert_eq!(*renbt_epoch_ptr, 42); - } - - // is_signer - assert_eq!(offset_of!(AccountInfo, is_signer), 40); - let is_signer_ptr = (account_info_addr + 40) as *const bool; - unsafe { - assert!(*is_signer_ptr); - } - - // is_writable - assert_eq!(offset_of!(AccountInfo, is_writable), 41); - let is_writable_ptr = (account_info_addr + 41) as *const bool; - unsafe { - assert!(!*is_writable_ptr); - } - - // executable - assert_eq!(offset_of!(AccountInfo, executable), 42); - let executable_ptr = (account_info_addr + 42) as *const bool; - unsafe { - assert!(*executable_ptr); - } - } + solana_account_info::check_type_assumptions(); } #[cfg(test)] diff --git a/program/src/program_error.rs b/program/src/program_error.rs index 8c2901583..975a5e312 100644 --- a/program/src/program_error.rs +++ b/program/src/program_error.rs @@ -1,7 +1,5 @@ -#[allow(deprecated)] -pub use solana_program_error::PrintProgramError; pub use { - solana_instruction::error::{ + solana_instruction_error::{ ACCOUNT_ALREADY_INITIALIZED, ACCOUNT_BORROW_FAILED, ACCOUNT_DATA_TOO_SMALL, ACCOUNT_NOT_RENT_EXEMPT, ARITHMETIC_OVERFLOW, BORSH_IO_ERROR, BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS, CUSTOM_ZERO, ILLEGAL_OWNER, IMMUTABLE, diff --git a/program/src/program_utils.rs b/program/src/program_utils.rs deleted file mode 100644 index 823cd9881..000000000 --- a/program/src/program_utils.rs +++ /dev/null @@ -1 +0,0 @@ -pub use solana_bincode::limited_deserialize; diff --git a/program/src/stake.rs b/program/src/stake.rs deleted file mode 100644 index 01125e1f0..000000000 --- a/program/src/stake.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![deprecated(since = "2.3.0", note = "Use solana-stake-interface instead")] -pub use solana_stake_interface::{ - config, stake_flags, state, tools, MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION, -}; - -pub mod instruction { - pub use solana_stake_interface::{error::StakeError, instruction::*}; -} - -pub mod program { - pub use solana_sdk_ids::stake::{check_id, id, ID}; -} diff --git a/program/src/stake_history.rs b/program/src/stake_history.rs deleted file mode 100644 index 9ed1de828..000000000 --- a/program/src/stake_history.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![deprecated(since = "2.3.0", note = "Use `solana-stake-interface` crate instead")] -pub use { - crate::sysvar::stake_history::{ - StakeHistory, StakeHistoryEntry, StakeHistoryGetEntry, MAX_ENTRIES, - }, - solana_clock::Epoch, -}; diff --git a/program/src/system_instruction.rs b/program/src/system_instruction.rs deleted file mode 100644 index b090b8b1e..000000000 --- a/program/src/system_instruction.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![deprecated(since = "2.3.0", note = "Use `solana_system_interface` crate instead")] - -pub use solana_system_interface::{ - error::SystemError, - instruction::{ - advance_nonce_account, allocate, allocate_with_seed, assign, assign_with_seed, - authorize_nonce_account, create_account, create_account_with_seed, create_nonce_account, - create_nonce_account_with_seed, transfer, transfer_many, transfer_with_seed, - upgrade_nonce_account, withdraw_nonce_account, SystemInstruction, - }, - MAX_PERMITTED_ACCOUNTS_DATA_ALLOCATIONS_PER_TRANSACTION, MAX_PERMITTED_DATA_LENGTH, -}; diff --git a/program/src/system_program.rs b/program/src/system_program.rs deleted file mode 100644 index 66bc64735..000000000 --- a/program/src/system_program.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![deprecated(since = "2.3.0", note = "Use `solana_sdk_ids::system_program` instead")] -//! The [system native program][np]. -//! -//! [np]: https://docs.solanalabs.com/runtime/programs#system-program -pub use solana_sdk_ids::system_program::{check_id, id, ID}; diff --git a/program/src/sysvar.rs b/program/src/sysvar.rs index 9de44e9ce..cd17415ca 100644 --- a/program/src/sysvar.rs +++ b/program/src/sysvar.rs @@ -5,9 +5,8 @@ pub use solana_sysvar_id::{declare_deprecated_sysvar_id, declare_sysvar_id, Sysv pub use { solana_sdk_ids::sysvar::{check_id, id, ID}, solana_sysvar::{ - clock, epoch_rewards, epoch_schedule, fees, is_sysvar_id, last_restart_slot, - recent_blockhashes, rent, rewards, slot_hashes, slot_history, stake_history, Sysvar, - ALL_IDS, + clock, epoch_rewards, epoch_schedule, fees, last_restart_slot, recent_blockhashes, rent, + rewards, slot_hashes, slot_history, Sysvar, SysvarSerialize, }, }; @@ -27,7 +26,7 @@ pub mod instructions { #[allow(deprecated)] pub use solana_instructions_sysvar::{ get_instruction_relative, load_current_index_checked, load_instruction_at_checked, - store_current_index, Instructions, + Instructions, }; #[deprecated(since = "2.2.0", note = "Use solana-sdk-ids crate instead")] pub use solana_sdk_ids::sysvar::instructions::{check_id, id, ID}; diff --git a/program/src/wasm/mod.rs b/program/src/wasm/mod.rs deleted file mode 100644 index 337dfb1db..000000000 --- a/program/src/wasm/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! solana-program Javascript interface -#![cfg(target_arch = "wasm32")] -#[deprecated(since = "2.2.0", note = "Use solana_instruction::wasm instead.")] -pub use solana_instruction::wasm as instructions; -use wasm_bindgen::prelude::*; -// This module is intentionally left empty. The wasm system instruction impl can be -// found in the `solana-system-interface` crate. -pub mod system_instruction {} - -/// Initialize Javascript logging and panic handler -#[wasm_bindgen] -pub fn solana_program_init() { - use std::sync::Once; - static INIT: Once = Once::new(); - - INIT.call_once(|| { - std::panic::set_hook(Box::new(console_error_panic_hook::hook)); - console_log::init_with_level(log::Level::Info).unwrap(); - }); -} - -pub fn display_to_jsvalue(display: T) -> JsValue { - display.to_string().into() -} diff --git a/pubkey/Cargo.toml b/pubkey/Cargo.toml index 91dad8ad4..0534490f4 100644 --- a/pubkey/Cargo.toml +++ b/pubkey/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-pubkey" description = "Solana account addresses" documentation = "https://docs.rs/solana-pubkey" version = "2.4.0" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -10,72 +11,25 @@ license = { workspace = true } edition = { workspace = true } [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +targets = ["x86_64-unknown-linux-gnu"] all-features = true rustdoc-args = ["--cfg=docsrs"] [features] -borsh = ["dep:borsh", "dep:borsh0-10", "std"] -bytemuck = ["dep:bytemuck", "dep:bytemuck_derive"] -curve25519 = ["dep:curve25519-dalek", "sha2"] +borsh = ["solana-address/borsh"] +bytemuck = ["solana-address/bytemuck"] +curve25519 = ["solana-address/curve25519"] default = ["std"] -dev-context-only-utils = ["dep:arbitrary", "rand"] -frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro", "std"] -rand = ["dep:rand", "std"] -serde = ["dep:serde", "dep:serde_derive"] -sha2 = ["dep:solana-sha256-hasher", "solana-sha256-hasher/sha2"] -std = [] +dev-context-only-utils = ["solana-address/dev-context-only-utils"] +frozen-abi = ["solana-address/frozen-abi"] +rand = ["dep:rand", "solana-address/rand"] +serde = ["solana-address/serde"] +sha2 = ["solana-address/sha2"] +std = ["solana-address/std"] [dependencies] -arbitrary = { workspace = true, features = ["derive"], optional = true } -borsh = { workspace = true, optional = true } -borsh0-10 = { package = "borsh", version = "0.10.3", optional = true } -bytemuck = { workspace = true, optional = true } -bytemuck_derive = { workspace = true, optional = true } -five8 = { workspace = true } -five8_const = { workspace = true } -num-traits = { workspace = true } rand = { workspace = true, optional = true } -serde = { workspace = true, optional = true } -serde_derive = { workspace = true, optional = true } -solana-atomic-u64 = { workspace = true } -solana-decode-error = { workspace = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-frozen-abi-macro = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-sanitize = { workspace = true } - -[target.'cfg(not(target_os = "solana"))'.dependencies] -curve25519-dalek = { workspace = true, optional = true } -solana-sha256-hasher = { workspace = true, optional = true } - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { workspace = true, features = ["js", "wasm-bindgen"] } -js-sys = { workspace = true } -wasm-bindgen = { workspace = true } - -[target.'cfg(target_os = "solana")'.dependencies] -solana-define-syscall = { workspace = true } -solana-sha256-hasher = { workspace = true } - -[dev-dependencies] -anyhow = { workspace = true } -arbitrary = { workspace = true, features = ["derive"] } -bs58 = { workspace = true, features = ["alloc"] } -# circular dev deps need to be path deps for `cargo publish` to be happy, -# and for now the doc tests need solana-program -solana-program = { path = "../program" } -solana-pubkey = { path = ".", features = [ - "borsh", - "curve25519", - "dev-context-only-utils", - "std", -] } -strum = { workspace = true } -strum_macros = { workspace = true } +solana-address = { workspace = true, features = ["atomic", "decode", "error", "sanitize", "sha2", "syscalls"] } [lints] workspace = true diff --git a/pubkey/src/lib.rs b/pubkey/src/lib.rs index ca143d865..f992f2dd7 100644 --- a/pubkey/src/lib.rs +++ b/pubkey/src/lib.rs @@ -4,1209 +4,27 @@ #![cfg_attr(feature = "frozen-abi", feature(min_specialization))] #![allow(clippy::arithmetic_side_effects)] -#[cfg(any(feature = "std", target_arch = "wasm32"))] -extern crate std; -#[cfg(feature = "dev-context-only-utils")] -use arbitrary::Arbitrary; -#[cfg(feature = "bytemuck")] -use bytemuck_derive::{Pod, Zeroable}; -#[cfg(feature = "serde")] -use serde_derive::{Deserialize, Serialize}; -#[cfg(any(feature = "std", target_arch = "wasm32"))] -use std::vec::Vec; -#[cfg(feature = "borsh")] -use { - borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, - std::string::ToString, -}; -use { - core::{ - array, - convert::{Infallible, TryFrom}, - fmt, - hash::{Hash, Hasher}, - mem, - str::{from_utf8_unchecked, FromStr}, - }, - num_traits::{FromPrimitive, ToPrimitive}, -}; -#[cfg(target_arch = "wasm32")] -use { - js_sys::{Array, Uint8Array}, - wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}, -}; - -#[cfg(target_os = "solana")] -pub mod syscalls; - -/// Number of bytes in a pubkey -pub const PUBKEY_BYTES: usize = 32; -/// maximum length of derived `Pubkey` seed -pub const MAX_SEED_LEN: usize = 32; -/// Maximum number of seeds -pub const MAX_SEEDS: usize = 16; -/// Maximum string length of a base58 encoded pubkey -const MAX_BASE58_LEN: usize = 44; - -#[cfg(any(target_os = "solana", feature = "sha2", feature = "curve25519"))] -const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress"; - -/// Copied from `solana_program::entrypoint::SUCCESS` -/// to avoid a `solana_program` dependency -#[cfg(target_os = "solana")] -const SUCCESS: u64 = 0; - -// Use strum when testing to ensure our FromPrimitive -// impl is exhaustive -#[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))] -#[cfg_attr(feature = "serde", derive(Serialize))] -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PubkeyError { - /// Length of the seed is too long for address generation - MaxSeedLengthExceeded, - InvalidSeeds, - IllegalOwner, -} - -impl ToPrimitive for PubkeyError { - #[inline] - fn to_i64(&self) -> Option { - Some(match *self { - PubkeyError::MaxSeedLengthExceeded => PubkeyError::MaxSeedLengthExceeded as i64, - PubkeyError::InvalidSeeds => PubkeyError::InvalidSeeds as i64, - PubkeyError::IllegalOwner => PubkeyError::IllegalOwner as i64, - }) - } - #[inline] - fn to_u64(&self) -> Option { - self.to_i64().map(|x| x as u64) - } -} - -impl FromPrimitive for PubkeyError { - #[inline] - fn from_i64(n: i64) -> Option { - if n == PubkeyError::MaxSeedLengthExceeded as i64 { - Some(PubkeyError::MaxSeedLengthExceeded) - } else if n == PubkeyError::InvalidSeeds as i64 { - Some(PubkeyError::InvalidSeeds) - } else if n == PubkeyError::IllegalOwner as i64 { - Some(PubkeyError::IllegalOwner) - } else { - None - } - } - #[inline] - fn from_u64(n: u64) -> Option { - Self::from_i64(n as i64) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for PubkeyError {} - -impl fmt::Display for PubkeyError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - PubkeyError::MaxSeedLengthExceeded => { - f.write_str("Length of the seed is too long for address generation") - } - PubkeyError::InvalidSeeds => { - f.write_str("Provided seeds do not result in a valid address") - } - PubkeyError::IllegalOwner => f.write_str("Provided owner is not allowed"), - } - } -} - -#[allow(deprecated)] -impl solana_decode_error::DecodeError for PubkeyError { - fn type_of() -> &'static str { - "PubkeyError" - } -} -impl From for PubkeyError { - fn from(error: u64) -> Self { - match error { - 0 => PubkeyError::MaxSeedLengthExceeded, - 1 => PubkeyError::InvalidSeeds, - 2 => PubkeyError::IllegalOwner, - _ => panic!("Unsupported PubkeyError"), - } - } -} - -/// The address of a [Solana account][acc]. -/// -/// Some account addresses are [ed25519] public keys, with corresponding secret -/// keys that are managed off-chain. Often, though, account addresses do not -/// have corresponding secret keys — as with [_program derived -/// addresses_][pdas] — or the secret key is not relevant to the operation -/// of a program, and may have even been disposed of. As running Solana programs -/// can not safely create or manage secret keys, the full [`Keypair`] is not -/// defined in `solana-program` but in `solana-sdk`. -/// -/// [acc]: https://solana.com/docs/core/accounts -/// [ed25519]: https://ed25519.cr.yp.to/ -/// [pdas]: https://solana.com/docs/core/cpi#program-derived-addresses -/// [`Keypair`]: https://docs.rs/solana-sdk/latest/solana_sdk/signer/keypair/struct.Keypair.html -#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] -#[repr(transparent)] -#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] -#[cfg_attr( - feature = "borsh", - derive(BorshSerialize, BorshDeserialize), - borsh(crate = "borsh") -)] -#[cfg_attr(all(feature = "borsh", feature = "std"), derive(BorshSchema))] -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))] -#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))] -pub struct Pubkey(pub(crate) [u8; 32]); - -/// Custom impl of Hash for Pubkey -/// allows us to skip hashing the length of the pubkey -/// which is always the same anyway -impl Hash for Pubkey { - fn hash(&self, state: &mut H) { - state.write(self.as_array()); - } -} - -#[cfg(all(feature = "rand", not(target_os = "solana")))] -mod hasher { - use { - crate::PUBKEY_BYTES, - core::{ - cell::Cell, - hash::{BuildHasher, Hasher}, - mem, - }, - rand::{thread_rng, Rng}, - }; - - /// A faster, but less collision resistant hasher for pubkeys. - /// - /// Specialized hasher that uses a random 8 bytes subslice of the - /// pubkey as the hash value. Should not be used when collisions - /// might be used to mount DOS attacks. - /// - /// Using this results in about 4x faster lookups in a typical hashmap. - #[derive(Default)] - pub struct PubkeyHasher { - offset: usize, - state: u64, - } - - impl Hasher for PubkeyHasher { - #[inline] - fn finish(&self) -> u64 { - self.state - } - #[inline] - fn write(&mut self, bytes: &[u8]) { - debug_assert_eq!( - bytes.len(), - PUBKEY_BYTES, - "This hasher is intended to be used with pubkeys and nothing else" - ); - // This slice/unwrap can never panic since offset is < PUBKEY_BYTES - mem::size_of::() - let chunk: &[u8; mem::size_of::()] = bytes - [self.offset..self.offset + mem::size_of::()] - .try_into() - .unwrap(); - self.state = u64::from_ne_bytes(*chunk); - } - } - - /// A builder for faster, but less collision resistant hasher for pubkeys. - /// - /// Initializes `PubkeyHasher` instances that use an 8-byte - /// slice of the pubkey as the hash value. Should not be used when - /// collisions might be used to mount DOS attacks. - /// - /// Using this results in about 4x faster lookups in a typical hashmap. - #[derive(Clone)] - pub struct PubkeyHasherBuilder { - offset: usize, - } - - impl Default for PubkeyHasherBuilder { - /// Default construct the PubkeyHasherBuilder. - /// - /// The position of the slice is determined initially - /// through random draw and then by incrementing a thread-local - /// This way each hashmap can be expected to use a slightly different - /// slice. This is essentially the same mechanism as what is used by - /// `RandomState` - fn default() -> Self { - std::thread_local!(static OFFSET: Cell = { - let mut rng = thread_rng(); - Cell::new(rng.gen_range(0..PUBKEY_BYTES - mem::size_of::())) - }); - - let offset = OFFSET.with(|offset| { - let mut next_offset = offset.get() + 1; - if next_offset > PUBKEY_BYTES - mem::size_of::() { - next_offset = 0; - } - offset.set(next_offset); - next_offset - }); - PubkeyHasherBuilder { offset } - } - } - - impl BuildHasher for PubkeyHasherBuilder { - type Hasher = PubkeyHasher; - #[inline] - fn build_hasher(&self) -> Self::Hasher { - PubkeyHasher { - offset: self.offset, - state: 0, - } - } - } - - #[cfg(test)] - mod tests { - use { - super::PubkeyHasherBuilder, - crate::Pubkey, - core::hash::{BuildHasher, Hasher}, - }; - #[test] - fn test_pubkey_hasher_builder() { - let key = Pubkey::new_unique(); - let builder = PubkeyHasherBuilder::default(); - let mut hasher1 = builder.build_hasher(); - let mut hasher2 = builder.build_hasher(); - hasher1.write(key.as_array()); - hasher2.write(key.as_array()); - assert_eq!( - hasher1.finish(), - hasher2.finish(), - "Hashers made with same builder should be identical" - ); - // Make sure that when we make new builders we get different slices - // chosen for hashing - let builder2 = PubkeyHasherBuilder::default(); - for _ in 0..64 { - let mut hasher3 = builder2.build_hasher(); - hasher3.write(key.as_array()); - std::dbg!(hasher1.finish()); - std::dbg!(hasher3.finish()); - if hasher1.finish() != hasher3.finish() { - return; - } - } - panic!("Hashers built with different builder should be different due to random offset"); - } - - #[test] - fn test_pubkey_hasher() { - let key1 = Pubkey::new_unique(); - let key2 = Pubkey::new_unique(); - let builder = PubkeyHasherBuilder::default(); - let mut hasher1 = builder.build_hasher(); - let mut hasher2 = builder.build_hasher(); - hasher1.write(key1.as_array()); - hasher2.write(key2.as_array()); - assert_ne!(hasher1.finish(), hasher2.finish()); - } - } -} -#[cfg(all(feature = "rand", not(target_os = "solana")))] -pub use hasher::{PubkeyHasher, PubkeyHasherBuilder}; - -impl solana_sanitize::Sanitize for Pubkey {} - -// Use strum when testing to ensure our FromPrimitive -// impl is exhaustive -#[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))] -#[cfg_attr(feature = "serde", derive(Serialize))] -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ParsePubkeyError { - WrongSize, - Invalid, -} - -impl ToPrimitive for ParsePubkeyError { - #[inline] - fn to_i64(&self) -> Option { - Some(match *self { - ParsePubkeyError::WrongSize => ParsePubkeyError::WrongSize as i64, - ParsePubkeyError::Invalid => ParsePubkeyError::Invalid as i64, - }) - } - #[inline] - fn to_u64(&self) -> Option { - self.to_i64().map(|x| x as u64) - } -} - -impl FromPrimitive for ParsePubkeyError { - #[inline] - fn from_i64(n: i64) -> Option { - if n == ParsePubkeyError::WrongSize as i64 { - Some(ParsePubkeyError::WrongSize) - } else if n == ParsePubkeyError::Invalid as i64 { - Some(ParsePubkeyError::Invalid) - } else { - None - } - } - #[inline] - fn from_u64(n: u64) -> Option { - Self::from_i64(n as i64) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for ParsePubkeyError {} - -impl fmt::Display for ParsePubkeyError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - ParsePubkeyError::WrongSize => f.write_str("String is the wrong size"), - ParsePubkeyError::Invalid => f.write_str("Invalid Base58 string"), - } - } -} - -impl From for ParsePubkeyError { - fn from(_: Infallible) -> Self { - unreachable!("Infallible uninhabited"); - } -} - -#[allow(deprecated)] -impl solana_decode_error::DecodeError for ParsePubkeyError { - fn type_of() -> &'static str { - "ParsePubkeyError" - } -} - -impl FromStr for Pubkey { - type Err = ParsePubkeyError; - - fn from_str(s: &str) -> Result { - use five8::DecodeError; - if s.len() > MAX_BASE58_LEN { - return Err(ParsePubkeyError::WrongSize); - } - let mut bytes = [0; PUBKEY_BYTES]; - five8::decode_32(s, &mut bytes).map_err(|e| match e { - DecodeError::InvalidChar(_) => ParsePubkeyError::Invalid, - DecodeError::TooLong - | DecodeError::TooShort - | DecodeError::LargestTermTooHigh - | DecodeError::OutputTooLong => ParsePubkeyError::WrongSize, - })?; - Ok(Pubkey(bytes)) - } -} - -impl From<&Pubkey> for Pubkey { - #[inline] - fn from(value: &Pubkey) -> Self { - *value - } -} - -impl From<[u8; 32]> for Pubkey { - #[inline] - fn from(from: [u8; 32]) -> Self { - Self(from) - } -} - -impl TryFrom<&[u8]> for Pubkey { - type Error = array::TryFromSliceError; - - #[inline] - fn try_from(pubkey: &[u8]) -> Result { - <[u8; 32]>::try_from(pubkey).map(Self::from) - } -} - -#[cfg(any(feature = "std", target_arch = "wasm32"))] -impl TryFrom> for Pubkey { - type Error = Vec; - - #[inline] - fn try_from(pubkey: Vec) -> Result { - <[u8; 32]>::try_from(pubkey).map(Self::from) - } -} - -impl TryFrom<&str> for Pubkey { - type Error = ParsePubkeyError; - fn try_from(s: &str) -> Result { - Pubkey::from_str(s) - } -} - // If target_os = "solana", then this panics so there are no dependencies. // When target_os != "solana", this should be opt-in so users // don't need the curve25519 dependency. #[cfg(any(target_os = "solana", feature = "curve25519"))] -#[allow(clippy::used_underscore_binding)] -pub fn bytes_are_curve_point>(_bytes: T) -> bool { - #[cfg(not(target_os = "solana"))] - { - let Ok(compressed_edwards_y) = - curve25519_dalek::edwards::CompressedEdwardsY::from_slice(_bytes.as_ref()) - else { - return false; - }; - compressed_edwards_y.decompress().is_some() - } - #[cfg(target_os = "solana")] - unimplemented!(); -} - -impl Pubkey { - pub const fn new_from_array(pubkey_array: [u8; 32]) -> Self { - Self(pubkey_array) - } - - /// Decode a string into a Pubkey, usable in a const context - pub const fn from_str_const(s: &str) -> Self { - let id_array = five8_const::decode_32_const(s); - Pubkey::new_from_array(id_array) - } - - /// unique Pubkey for tests and benchmarks. - pub fn new_unique() -> Self { - use solana_atomic_u64::AtomicU64; - static I: AtomicU64 = AtomicU64::new(1); - type T = u32; - const COUNTER_BYTES: usize = mem::size_of::(); - let mut b = [0u8; PUBKEY_BYTES]; - #[cfg(any(feature = "std", target_arch = "wasm32"))] - let mut i = I.fetch_add(1) as T; - #[cfg(not(any(feature = "std", target_arch = "wasm32")))] - let i = I.fetch_add(1) as T; - // use big endian representation to ensure that recent unique pubkeys - // are always greater than less recent unique pubkeys. - b[0..COUNTER_BYTES].copy_from_slice(&i.to_be_bytes()); - // fill the rest of the pubkey with pseudorandom numbers to make - // data statistically similar to real pubkeys. - #[cfg(any(feature = "std", target_arch = "wasm32"))] - { - let mut hash = std::hash::DefaultHasher::new(); - for slice in b[COUNTER_BYTES..].chunks_mut(COUNTER_BYTES) { - hash.write_u32(i); - i += 1; - slice.copy_from_slice(&hash.finish().to_ne_bytes()[0..COUNTER_BYTES]); - } - } - // if std is not available, just replicate last byte of the counter. - // this is not as good as a proper hash, but at least it is uniform - #[cfg(not(any(feature = "std", target_arch = "wasm32")))] - { - for b in b[COUNTER_BYTES..].iter_mut() { - *b = (i & 0xFF) as u8; - } - } - Self::from(b) - } - - // If target_os = "solana", then the solana_sha256_hasher crate will use - // syscalls which bring no dependencies. - // When target_os != "solana", this should be opt-in so users - // don't need the sha2 dependency. - #[cfg(any(target_os = "solana", feature = "sha2"))] - pub fn create_with_seed( - base: &Pubkey, - seed: &str, - owner: &Pubkey, - ) -> Result { - if seed.len() > MAX_SEED_LEN { - return Err(PubkeyError::MaxSeedLengthExceeded); - } - - let owner = owner.as_ref(); - if owner.len() >= PDA_MARKER.len() { - let slice = &owner[owner.len() - PDA_MARKER.len()..]; - if slice == PDA_MARKER { - return Err(PubkeyError::IllegalOwner); - } - } - let hash = solana_sha256_hasher::hashv(&[base.as_ref(), seed.as_ref(), owner]); - Ok(Pubkey::from(hash.to_bytes())) - } - - /// Find a valid [program derived address][pda] and its corresponding bump seed. - /// - /// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses - /// - /// Program derived addresses (PDAs) are account keys that only the program, - /// `program_id`, has the authority to sign. The address is of the same form - /// as a Solana `Pubkey`, except they are ensured to not be on the ed25519 - /// curve and thus have no associated private key. When performing - /// cross-program invocations the program can "sign" for the key by calling - /// [`invoke_signed`] and passing the same seeds used to generate the - /// address, along with the calculated _bump seed_, which this function - /// returns as the second tuple element. The runtime will verify that the - /// program associated with this address is the caller and thus authorized - /// to be the signer. - /// - /// [`invoke_signed`]: https://docs.rs/solana-program/latest/solana_program/program/fn.invoke_signed.html - /// - /// The `seeds` are application-specific, and must be carefully selected to - /// uniquely derive accounts per application requirements. It is common to - /// use static strings and other pubkeys as seeds. - /// - /// Because the program address must not lie on the ed25519 curve, there may - /// be seed and program id combinations that are invalid. For this reason, - /// an extra seed (the bump seed) is calculated that results in a - /// point off the curve. The bump seed must be passed as an additional seed - /// when calling `invoke_signed`. - /// - /// The processes of finding a valid program address is by trial and error, - /// and even though it is deterministic given a set of inputs it can take a - /// variable amount of time to succeed across different inputs. This means - /// that when called from an on-chain program it may incur a variable amount - /// of the program's compute budget. Programs that are meant to be very - /// performant may not want to use this function because it could take a - /// considerable amount of time. Programs that are already at risk - /// of exceeding their compute budget should call this with care since - /// there is a chance that the program's budget may be occasionally - /// and unpredictably exceeded. - /// - /// As all account addresses accessed by an on-chain Solana program must be - /// explicitly passed to the program, it is typical for the PDAs to be - /// derived in off-chain client programs, avoiding the compute cost of - /// generating the address on-chain. The address may or may not then be - /// verified by re-deriving it on-chain, depending on the requirements of - /// the program. This verification may be performed without the overhead of - /// re-searching for the bump key by using the [`create_program_address`] - /// function. - /// - /// [`create_program_address`]: Pubkey::create_program_address - /// - /// **Warning**: Because of the way the seeds are hashed there is a potential - /// for program address collisions for the same program id. The seeds are - /// hashed sequentially which means that seeds {"abcdef"}, {"abc", "def"}, - /// and {"ab", "cd", "ef"} will all result in the same program address given - /// the same program id. Since the chance of collision is local to a given - /// program id, the developer of that program must take care to choose seeds - /// that do not collide with each other. For seed schemes that are susceptible - /// to this type of hash collision, a common remedy is to insert separators - /// between seeds, e.g. transforming {"abc", "def"} into {"abc", "-", "def"}. - /// - /// # Panics - /// - /// Panics in the statistically improbable event that a bump seed could not be - /// found. Use [`try_find_program_address`] to handle this case. - /// - /// [`try_find_program_address`]: Pubkey::try_find_program_address - /// - /// Panics if any of the following are true: - /// - /// - the number of provided seeds is greater than, _or equal to_, [`MAX_SEEDS`], - /// - any individual seed's length is greater than [`MAX_SEED_LEN`]. - /// - /// # Examples - /// - /// This example illustrates a simple case of creating a "vault" account - /// which is derived from the payer account, but owned by an on-chain - /// program. The program derived address is derived in an off-chain client - /// program, which invokes an on-chain Solana program that uses the address - /// to create a new account owned and controlled by the program itself. - /// - /// By convention, the on-chain program will be compiled for use in two - /// different contexts: both on-chain, to interpret a custom program - /// instruction as a Solana transaction; and off-chain, as a library, so - /// that clients can share the instruction data structure, constructors, and - /// other common code. - /// - /// First the on-chain Solana program: - /// - /// ``` - /// # use borsh::{BorshSerialize, BorshDeserialize}; - /// # use solana_pubkey::Pubkey; - /// # use solana_program::{ - /// # entrypoint::ProgramResult, - /// # program::invoke_signed, - /// # system_instruction, - /// # account_info::{ - /// # AccountInfo, - /// # next_account_info, - /// # }, - /// # }; - /// // The custom instruction processed by our program. It includes the - /// // PDA's bump seed, which is derived by the client program. This - /// // definition is also imported into the off-chain client program. - /// // The computed address of the PDA will be passed to this program via - /// // the `accounts` vector of the `Instruction` type. - /// #[derive(BorshSerialize, BorshDeserialize, Debug)] - /// # #[borsh(crate = "borsh")] - /// pub struct InstructionData { - /// pub vault_bump_seed: u8, - /// pub lamports: u64, - /// } - /// - /// // The size in bytes of a vault account. The client program needs - /// // this information to calculate the quantity of lamports necessary - /// // to pay for the account's rent. - /// pub static VAULT_ACCOUNT_SIZE: u64 = 1024; - /// - /// // The entrypoint of the on-chain program, as provided to the - /// // `entrypoint!` macro. - /// fn process_instruction( - /// program_id: &Pubkey, - /// accounts: &[AccountInfo], - /// instruction_data: &[u8], - /// ) -> ProgramResult { - /// let account_info_iter = &mut accounts.iter(); - /// let payer = next_account_info(account_info_iter)?; - /// // The vault PDA, derived from the payer's address - /// let vault = next_account_info(account_info_iter)?; - /// - /// let mut instruction_data = instruction_data; - /// let instr = InstructionData::deserialize(&mut instruction_data)?; - /// let vault_bump_seed = instr.vault_bump_seed; - /// let lamports = instr.lamports; - /// let vault_size = VAULT_ACCOUNT_SIZE; - /// - /// // Invoke the system program to create an account while virtually - /// // signing with the vault PDA, which is owned by this caller program. - /// invoke_signed( - /// &system_instruction::create_account( - /// &payer.key, - /// &vault.key, - /// lamports, - /// vault_size, - /// &program_id, - /// ), - /// &[ - /// payer.clone(), - /// vault.clone(), - /// ], - /// // A slice of seed slices, each seed slice being the set - /// // of seeds used to generate one of the PDAs required by the - /// // callee program, the final seed being a single-element slice - /// // containing the `u8` bump seed. - /// &[ - /// &[ - /// b"vault", - /// payer.key.as_ref(), - /// &[vault_bump_seed], - /// ], - /// ] - /// )?; - /// - /// Ok(()) - /// } - /// ``` - /// - /// The client program: - /// - /// ``` - /// # use borsh::{BorshSerialize, BorshDeserialize}; - /// # use solana_program::example_mocks::{solana_sdk, solana_rpc_client}; - /// # use solana_pubkey::Pubkey; - /// # use solana_program::{ - /// # instruction::Instruction, - /// # hash::Hash, - /// # instruction::AccountMeta, - /// # system_program, - /// # }; - /// # use solana_sdk::{ - /// # signature::Keypair, - /// # signature::{Signer, Signature}, - /// # transaction::Transaction, - /// # }; - /// # use solana_rpc_client::rpc_client::RpcClient; - /// # use std::convert::TryFrom; - /// # use anyhow::Result; - /// # - /// # #[derive(BorshSerialize, BorshDeserialize, Debug)] - /// # #[borsh(crate = "borsh")] - /// # struct InstructionData { - /// # pub vault_bump_seed: u8, - /// # pub lamports: u64, - /// # } - /// # - /// # pub static VAULT_ACCOUNT_SIZE: u64 = 1024; - /// # - /// fn create_vault_account( - /// client: &RpcClient, - /// program_id: Pubkey, - /// payer: &Keypair, - /// ) -> Result<()> { - /// // Derive the PDA from the payer account, a string representing the unique - /// // purpose of the account ("vault"), and the address of our on-chain program. - /// let (vault_pubkey, vault_bump_seed) = Pubkey::find_program_address( - /// &[b"vault", payer.pubkey().as_ref()], - /// &program_id - /// ); - /// - /// // Get the amount of lamports needed to pay for the vault's rent - /// let vault_account_size = usize::try_from(VAULT_ACCOUNT_SIZE)?; - /// let lamports = client.get_minimum_balance_for_rent_exemption(vault_account_size)?; - /// - /// // The on-chain program's instruction data, imported from that program's crate. - /// let instr_data = InstructionData { - /// vault_bump_seed, - /// lamports, - /// }; - /// - /// // The accounts required by both our on-chain program and the system program's - /// // `create_account` instruction, including the vault's address. - /// let accounts = vec![ - /// AccountMeta::new(payer.pubkey(), true), - /// AccountMeta::new(vault_pubkey, false), - /// AccountMeta::new(system_program::ID, false), - /// ]; - /// - /// // Create the instruction by serializing our instruction data via borsh - /// let instruction = Instruction::new_with_borsh( - /// program_id, - /// &instr_data, - /// accounts, - /// ); - /// - /// let blockhash = client.get_latest_blockhash()?; - /// - /// let transaction = Transaction::new_signed_with_payer( - /// &[instruction], - /// Some(&payer.pubkey()), - /// &[payer], - /// blockhash, - /// ); - /// - /// client.send_and_confirm_transaction(&transaction)?; - /// - /// Ok(()) - /// } - /// # let program_id = Pubkey::new_unique(); - /// # let payer = Keypair::new(); - /// # let client = RpcClient::new(String::new()); - /// # - /// # create_vault_account(&client, program_id, &payer)?; - /// # - /// # Ok::<(), anyhow::Error>(()) - /// ``` - // If target_os = "solana", then the function will use - // syscalls which bring no dependencies. - // When target_os != "solana", this should be opt-in so users - // don't need the curve25519 dependency. - #[cfg(any(target_os = "solana", feature = "curve25519"))] - pub fn find_program_address(seeds: &[&[u8]], program_id: &Pubkey) -> (Pubkey, u8) { - Self::try_find_program_address(seeds, program_id) - .unwrap_or_else(|| panic!("Unable to find a viable program address bump seed")) - } - - /// Find a valid [program derived address][pda] and its corresponding bump seed. - /// - /// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses - /// - /// The only difference between this method and [`find_program_address`] - /// is that this one returns `None` in the statistically improbable event - /// that a bump seed cannot be found; or if any of `find_program_address`'s - /// preconditions are violated. - /// - /// See the documentation for [`find_program_address`] for a full description. - /// - /// [`find_program_address`]: Pubkey::find_program_address - // If target_os = "solana", then the function will use - // syscalls which bring no dependencies. - // When target_os != "solana", this should be opt-in so users - // don't need the curve25519 dependency. - #[cfg(any(target_os = "solana", feature = "curve25519"))] - #[allow(clippy::same_item_push)] - pub fn try_find_program_address(seeds: &[&[u8]], program_id: &Pubkey) -> Option<(Pubkey, u8)> { - // Perform the calculation inline, calling this from within a program is - // not supported - #[cfg(not(target_os = "solana"))] - { - let mut bump_seed = [u8::MAX]; - for _ in 0..u8::MAX { - { - let mut seeds_with_bump = seeds.to_vec(); - seeds_with_bump.push(&bump_seed); - match Self::create_program_address(&seeds_with_bump, program_id) { - Ok(address) => return Some((address, bump_seed[0])), - Err(PubkeyError::InvalidSeeds) => (), - _ => break, - } - } - bump_seed[0] -= 1; - } - None - } - // Call via a system call to perform the calculation - #[cfg(target_os = "solana")] - { - let mut bytes = [0; 32]; - let mut bump_seed = u8::MAX; - let result = unsafe { - crate::syscalls::sol_try_find_program_address( - seeds as *const _ as *const u8, - seeds.len() as u64, - program_id as *const _ as *const u8, - &mut bytes as *mut _ as *mut u8, - &mut bump_seed as *mut _ as *mut u8, - ) - }; - match result { - SUCCESS => Some((Pubkey::from(bytes), bump_seed)), - _ => None, - } - } - } - - /// Create a valid [program derived address][pda] without searching for a bump seed. - /// - /// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses - /// - /// Because this function does not create a bump seed, it may unpredictably - /// return an error for any given set of seeds and is not generally suitable - /// for creating program derived addresses. - /// - /// However, it can be used for efficiently verifying that a set of seeds plus - /// bump seed generated by [`find_program_address`] derives a particular - /// address as expected. See the example for details. - /// - /// See the documentation for [`find_program_address`] for a full description - /// of program derived addresses and bump seeds. - /// - /// [`find_program_address`]: Pubkey::find_program_address - /// - /// # Examples - /// - /// Creating a program derived address involves iteratively searching for a - /// bump seed for which the derived [`Pubkey`] does not lie on the ed25519 - /// curve. This search process is generally performed off-chain, with the - /// [`find_program_address`] function, after which the client passes the - /// bump seed to the program as instruction data. - /// - /// Depending on the application requirements, a program may wish to verify - /// that the set of seeds, plus the bump seed, do correctly generate an - /// expected address. - /// - /// The verification is performed by appending to the other seeds one - /// additional seed slice that contains the single `u8` bump seed, calling - /// `create_program_address`, checking that the return value is `Ok`, and - /// that the returned `Pubkey` has the expected value. - /// - /// ``` - /// # use solana_pubkey::Pubkey; - /// # let program_id = Pubkey::new_unique(); - /// let (expected_pda, bump_seed) = Pubkey::find_program_address(&[b"vault"], &program_id); - /// let actual_pda = Pubkey::create_program_address(&[b"vault", &[bump_seed]], &program_id)?; - /// assert_eq!(expected_pda, actual_pda); - /// # Ok::<(), anyhow::Error>(()) - /// ``` - // If target_os = "solana", then the function will use - // syscalls which bring no dependencies. - // When target_os != "solana", this should be opt-in so users - // don't need the curve225519 dep. - #[cfg(any(target_os = "solana", feature = "curve25519"))] - pub fn create_program_address( - seeds: &[&[u8]], - program_id: &Pubkey, - ) -> Result { - if seeds.len() > MAX_SEEDS { - return Err(PubkeyError::MaxSeedLengthExceeded); - } - for seed in seeds.iter() { - if seed.len() > MAX_SEED_LEN { - return Err(PubkeyError::MaxSeedLengthExceeded); - } - } - - // Perform the calculation inline, calling this from within a program is - // not supported - #[cfg(not(target_os = "solana"))] - { - let mut hasher = solana_sha256_hasher::Hasher::default(); - for seed in seeds.iter() { - hasher.hash(seed); - } - hasher.hashv(&[program_id.as_ref(), PDA_MARKER]); - let hash = hasher.result(); - - if bytes_are_curve_point(hash) { - return Err(PubkeyError::InvalidSeeds); - } - - Ok(Pubkey::from(hash.to_bytes())) - } - // Call via a system call to perform the calculation - #[cfg(target_os = "solana")] - { - let mut bytes = [0; 32]; - let result = unsafe { - crate::syscalls::sol_create_program_address( - seeds as *const _ as *const u8, - seeds.len() as u64, - program_id as *const _ as *const u8, - &mut bytes as *mut _ as *mut u8, - ) - }; - match result { - SUCCESS => Ok(Pubkey::from(bytes)), - _ => Err(result.into()), - } - } - } - - pub const fn to_bytes(self) -> [u8; 32] { - self.0 - } - - /// Return a reference to the `Pubkey`'s byte array. - #[inline(always)] - pub const fn as_array(&self) -> &[u8; 32] { - &self.0 - } - - // If target_os = "solana", then this panics so there are no dependencies. - // When target_os != "solana", this should be opt-in so users - // don't need the curve25519 dependency. - #[cfg(any(target_os = "solana", feature = "curve25519"))] - pub fn is_on_curve(&self) -> bool { - bytes_are_curve_point(self) - } - - /// Log a `Pubkey` from a program - pub fn log(&self) { - #[cfg(target_os = "solana")] - unsafe { - crate::syscalls::sol_log_pubkey(self.as_ref() as *const _ as *const u8) - }; - - #[cfg(all(not(target_os = "solana"), feature = "std"))] - std::println!("{}", std::string::ToString::to_string(&self)); - } -} - -impl AsRef<[u8]> for Pubkey { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Pubkey { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - -fn write_as_base58(f: &mut fmt::Formatter, p: &Pubkey) -> fmt::Result { - let mut out = [0u8; MAX_BASE58_LEN]; - let len = five8::encode_32(&p.0, &mut out) as usize; - // any sequence of base58 chars is valid utf8 - let as_str = unsafe { from_utf8_unchecked(&out[..len]) }; - f.write_str(as_str) -} - -impl fmt::Debug for Pubkey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write_as_base58(f, self) - } -} - -impl fmt::Display for Pubkey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write_as_base58(f, self) - } -} - -#[cfg(feature = "borsh")] -impl borsh0_10::de::BorshDeserialize for Pubkey { - fn deserialize_reader( - reader: &mut R, - ) -> Result { - Ok(Self(borsh0_10::BorshDeserialize::deserialize_reader( - reader, - )?)) - } -} - -#[cfg(feature = "borsh")] -macro_rules! impl_borsh_schema { - ($borsh:ident) => { - impl $borsh::BorshSchema for Pubkey - where - [u8; 32]: $borsh::BorshSchema, - { - fn declaration() -> $borsh::schema::Declaration { - std::string::String::from("Pubkey") - } - fn add_definitions_recursively( - definitions: &mut $borsh::maybestd::collections::HashMap< - $borsh::schema::Declaration, - $borsh::schema::Definition, - >, - ) { - let fields = $borsh::schema::Fields::UnnamedFields(<[_]>::into_vec( - $borsh::maybestd::boxed::Box::new([ - <[u8; 32] as $borsh::BorshSchema>::declaration(), - ]), - )); - let definition = $borsh::schema::Definition::Struct { fields }; - ::add_definition( - ::declaration(), - definition, - definitions, - ); - <[u8; 32] as $borsh::BorshSchema>::add_definitions_recursively(definitions); - } - } - }; -} -#[cfg(feature = "borsh")] -impl_borsh_schema!(borsh0_10); - -#[cfg(feature = "borsh")] -macro_rules! impl_borsh_serialize { - ($borsh:ident) => { - impl $borsh::ser::BorshSerialize for Pubkey { - fn serialize( - &self, - writer: &mut W, - ) -> ::core::result::Result<(), $borsh::maybestd::io::Error> { - $borsh::BorshSerialize::serialize(&self.0, writer)?; - Ok(()) - } - } - }; -} -#[cfg(feature = "borsh")] -impl_borsh_serialize!(borsh0_10); - -#[cfg(all(target_arch = "wasm32", feature = "curve25519"))] -fn js_value_to_seeds_vec(array_of_uint8_arrays: &[JsValue]) -> Result>, JsValue> { - let vec_vec_u8 = array_of_uint8_arrays - .iter() - .filter_map(|u8_array| { - u8_array - .dyn_ref::() - .map(|u8_array| u8_array.to_vec()) - }) - .collect::>(); - - if vec_vec_u8.len() != array_of_uint8_arrays.len() { - Err("Invalid Array of Uint8Arrays".into()) - } else { - Ok(vec_vec_u8) - } -} - -#[cfg(target_arch = "wasm32")] -fn display_to_jsvalue(display: T) -> JsValue { - std::string::ToString::to_string(&display).into() -} - -#[allow(non_snake_case)] -#[cfg(target_arch = "wasm32")] -#[wasm_bindgen] -impl Pubkey { - /// Create a new Pubkey object - /// - /// * `value` - optional public key as a base58 encoded string, `Uint8Array`, `[number]` - #[wasm_bindgen(constructor)] - pub fn constructor(value: JsValue) -> Result { - if let Some(base58_str) = value.as_string() { - base58_str.parse::().map_err(display_to_jsvalue) - } else if let Some(uint8_array) = value.dyn_ref::() { - Pubkey::try_from(uint8_array.to_vec()) - .map_err(|err| JsValue::from(std::format!("Invalid Uint8Array pubkey: {err:?}"))) - } else if let Some(array) = value.dyn_ref::() { - let mut bytes = std::vec![]; - let iterator = js_sys::try_iter(&array.values())?.expect("array to be iterable"); - for x in iterator { - let x = x?; - - if let Some(n) = x.as_f64() { - if n >= 0. && n <= 255. { - bytes.push(n as u8); - continue; - } - } - return Err(std::format!("Invalid array argument: {:?}", x).into()); - } - Pubkey::try_from(bytes) - .map_err(|err| JsValue::from(std::format!("Invalid Array pubkey: {err:?}"))) - } else if value.is_undefined() { - Ok(Pubkey::default()) - } else { - Err("Unsupported argument".into()) - } - } - - /// Return the base58 string representation of the public key - pub fn toString(&self) -> std::string::String { - std::string::ToString::to_string(self) - } - - /// Check if a `Pubkey` is on the ed25519 curve. - #[cfg(feature = "curve25519")] - pub fn isOnCurve(&self) -> bool { - self.is_on_curve() - } - - /// Checks if two `Pubkey`s are equal - pub fn equals(&self, other: &Pubkey) -> bool { - self == other - } - - /// Return the `Uint8Array` representation of the public key - pub fn toBytes(&self) -> std::boxed::Box<[u8]> { - self.0.clone().into() - } - - /// Derive a Pubkey from another Pubkey, string seed, and a program id - #[cfg(feature = "sha2")] - pub fn createWithSeed(base: &Pubkey, seed: &str, owner: &Pubkey) -> Result { - Pubkey::create_with_seed(base, seed, owner).map_err(display_to_jsvalue) - } - - /// Derive a program address from seeds and a program id - #[cfg(feature = "curve25519")] - pub fn createProgramAddress( - seeds: std::boxed::Box<[JsValue]>, - program_id: &Pubkey, - ) -> Result { - let seeds_vec = js_value_to_seeds_vec(&seeds)?; - let seeds_slice = seeds_vec - .iter() - .map(|seed| seed.as_slice()) - .collect::>(); - - Pubkey::create_program_address(seeds_slice.as_slice(), program_id) - .map_err(display_to_jsvalue) - } - - /// Find a valid program address - /// - /// Returns: - /// * `[PubKey, number]` - the program address and bump seed - #[cfg(feature = "curve25519")] - pub fn findProgramAddress( - seeds: std::boxed::Box<[JsValue]>, - program_id: &Pubkey, - ) -> Result { - let seeds_vec = js_value_to_seeds_vec(&seeds)?; - let seeds_slice = seeds_vec - .iter() - .map(|seed| seed.as_slice()) - .collect::>(); - - let (address, bump_seed) = Pubkey::find_program_address(seeds_slice.as_slice(), program_id); +pub use solana_address::bytes_are_curve_point; +#[cfg(target_os = "solana")] +pub use solana_address::syscalls; +pub use solana_address::{ + address as pubkey, + error::{AddressError as PubkeyError, ParseAddressError as ParsePubkeyError}, + Address as Pubkey, ADDRESS_BYTES as PUBKEY_BYTES, MAX_SEEDS, MAX_SEED_LEN, +}; +#[cfg(all(feature = "rand", not(target_os = "solana")))] +pub use solana_address::{ + AddressHasher as PubkeyHasher, AddressHasherBuilder as PubkeyHasherBuilder, +}; - let result = Array::new_with_length(2); - result.set(0, address.into()); - result.set(1, bump_seed.into()); - Ok(result.into()) - } +/// New random `Pubkey` for tests and benchmarks. +#[cfg(all(feature = "rand", not(target_os = "solana")))] +pub fn new_rand() -> Pubkey { + Pubkey::from(rand::random::<[u8; PUBKEY_BYTES]>()) } /// Convenience macro to declare a static public key and functions to interact with it. @@ -1232,9 +50,9 @@ impl Pubkey { /// ``` #[macro_export] macro_rules! declare_id { - ($address:expr) => { + ($pubkey:expr) => { /// The const program ID. - pub const ID: $crate::Pubkey = $crate::Pubkey::from_str_const($address); + pub const ID: $crate::Pubkey = $crate::Pubkey::from_str_const($pubkey); /// Returns `true` if given pubkey is the program ID. // TODO make this const once `derive_const` makes it out of nightly @@ -1259,9 +77,9 @@ macro_rules! declare_id { /// Same as [`declare_id`] except that it reports that this ID has been deprecated. #[macro_export] macro_rules! declare_deprecated_id { - ($address:expr) => { + ($pubkey:expr) => { /// The const program ID. - pub const ID: $crate::Pubkey = $crate::Pubkey::from_str_const($address); + pub const ID: $crate::Pubkey = $crate::Pubkey::from_str_const($pubkey); /// Returns `true` if given pubkey is the program ID. // TODO make this const once `derive_const` makes it out of nightly @@ -1285,323 +103,3 @@ macro_rules! declare_deprecated_id { } }; } - -/// Convenience macro to define a static public key. -/// -/// Input: a single literal base58 string representation of a Pubkey. -/// -/// # Example -/// -/// ``` -/// use std::str::FromStr; -/// use solana_pubkey::{pubkey, Pubkey}; -/// -/// static ID: Pubkey = pubkey!("My11111111111111111111111111111111111111111"); -/// -/// let my_id = Pubkey::from_str("My11111111111111111111111111111111111111111").unwrap(); -/// assert_eq!(ID, my_id); -/// ``` -#[macro_export] -macro_rules! pubkey { - ($input:literal) => { - $crate::Pubkey::from_str_const($input) - }; -} - -/// New random Pubkey for tests and benchmarks. -#[cfg(all(feature = "rand", not(target_os = "solana")))] -pub fn new_rand() -> Pubkey { - Pubkey::from(rand::random::<[u8; PUBKEY_BYTES]>()) -} - -#[cfg(test)] -mod tests { - use {super::*, core::str::from_utf8, strum::IntoEnumIterator}; - - #[test] - fn test_new_unique() { - assert!(Pubkey::new_unique() != Pubkey::new_unique()); - } - - #[test] - fn pubkey_fromstr() { - let pubkey = Pubkey::new_unique(); - let mut pubkey_base58_str = bs58::encode(pubkey.0).into_string(); - - assert_eq!(pubkey_base58_str.parse::(), Ok(pubkey)); - - pubkey_base58_str.push_str(&bs58::encode(pubkey.0).into_string()); - assert_eq!( - pubkey_base58_str.parse::(), - Err(ParsePubkeyError::WrongSize) - ); - - pubkey_base58_str.truncate(pubkey_base58_str.len() / 2); - assert_eq!(pubkey_base58_str.parse::(), Ok(pubkey)); - - pubkey_base58_str.truncate(pubkey_base58_str.len() / 2); - assert_eq!( - pubkey_base58_str.parse::(), - Err(ParsePubkeyError::WrongSize) - ); - - let mut pubkey_base58_str = bs58::encode(pubkey.0).into_string(); - assert_eq!(pubkey_base58_str.parse::(), Ok(pubkey)); - - // throw some non-base58 stuff in there - pubkey_base58_str.replace_range(..1, "I"); - assert_eq!( - pubkey_base58_str.parse::(), - Err(ParsePubkeyError::Invalid) - ); - - // too long input string - // longest valid encoding - let mut too_long = bs58::encode(&[255u8; PUBKEY_BYTES]).into_string(); - // and one to grow on - too_long.push('1'); - assert_eq!(too_long.parse::(), Err(ParsePubkeyError::WrongSize)); - } - - #[test] - fn test_create_with_seed() { - assert!( - Pubkey::create_with_seed(&Pubkey::new_unique(), "☉", &Pubkey::new_unique()).is_ok() - ); - assert_eq!( - Pubkey::create_with_seed( - &Pubkey::new_unique(), - from_utf8(&[127; MAX_SEED_LEN + 1]).unwrap(), - &Pubkey::new_unique() - ), - Err(PubkeyError::MaxSeedLengthExceeded) - ); - assert!(Pubkey::create_with_seed( - &Pubkey::new_unique(), - "\ - \u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\ - ", - &Pubkey::new_unique() - ) - .is_ok()); - // utf-8 abuse ;) - assert_eq!( - Pubkey::create_with_seed( - &Pubkey::new_unique(), - "\ - x\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\u{10FFFF}\ - ", - &Pubkey::new_unique() - ), - Err(PubkeyError::MaxSeedLengthExceeded) - ); - - assert!(Pubkey::create_with_seed( - &Pubkey::new_unique(), - from_utf8(&[0; MAX_SEED_LEN]).unwrap(), - &Pubkey::new_unique(), - ) - .is_ok()); - - assert!( - Pubkey::create_with_seed(&Pubkey::new_unique(), "", &Pubkey::new_unique(),).is_ok() - ); - - assert_eq!( - Pubkey::create_with_seed( - &Pubkey::default(), - "limber chicken: 4/45", - &Pubkey::default(), - ), - Ok("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq" - .parse() - .unwrap()) - ); - } - - #[test] - fn test_create_program_address() { - let exceeded_seed = &[127; MAX_SEED_LEN + 1]; - let max_seed = &[0; MAX_SEED_LEN]; - let exceeded_seeds: &[&[u8]] = &[ - &[1], - &[2], - &[3], - &[4], - &[5], - &[6], - &[7], - &[8], - &[9], - &[10], - &[11], - &[12], - &[13], - &[14], - &[15], - &[16], - &[17], - ]; - let max_seeds: &[&[u8]] = &[ - &[1], - &[2], - &[3], - &[4], - &[5], - &[6], - &[7], - &[8], - &[9], - &[10], - &[11], - &[12], - &[13], - &[14], - &[15], - &[16], - ]; - let program_id = Pubkey::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap(); - let public_key = Pubkey::from_str("SeedPubey1111111111111111111111111111111111").unwrap(); - - assert_eq!( - Pubkey::create_program_address(&[exceeded_seed], &program_id), - Err(PubkeyError::MaxSeedLengthExceeded) - ); - assert_eq!( - Pubkey::create_program_address(&[b"short_seed", exceeded_seed], &program_id), - Err(PubkeyError::MaxSeedLengthExceeded) - ); - assert!(Pubkey::create_program_address(&[max_seed], &program_id).is_ok()); - assert_eq!( - Pubkey::create_program_address(exceeded_seeds, &program_id), - Err(PubkeyError::MaxSeedLengthExceeded) - ); - assert!(Pubkey::create_program_address(max_seeds, &program_id).is_ok()); - assert_eq!( - Pubkey::create_program_address(&[b"", &[1]], &program_id), - Ok("BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe" - .parse() - .unwrap()) - ); - assert_eq!( - Pubkey::create_program_address(&["☉".as_ref(), &[0]], &program_id), - Ok("13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19" - .parse() - .unwrap()) - ); - assert_eq!( - Pubkey::create_program_address(&[b"Talking", b"Squirrels"], &program_id), - Ok("2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk" - .parse() - .unwrap()) - ); - assert_eq!( - Pubkey::create_program_address(&[public_key.as_ref(), &[1]], &program_id), - Ok("976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL" - .parse() - .unwrap()) - ); - assert_ne!( - Pubkey::create_program_address(&[b"Talking", b"Squirrels"], &program_id).unwrap(), - Pubkey::create_program_address(&[b"Talking"], &program_id).unwrap(), - ); - } - - #[test] - fn test_pubkey_off_curve() { - // try a bunch of random input, all successful generated program - // addresses must land off the curve and be unique - let mut addresses = std::vec![]; - for _ in 0..1_000 { - let program_id = Pubkey::new_unique(); - let bytes1 = rand::random::<[u8; 10]>(); - let bytes2 = rand::random::<[u8; 32]>(); - if let Ok(program_address) = - Pubkey::create_program_address(&[&bytes1, &bytes2], &program_id) - { - assert!(!program_address.is_on_curve()); - assert!(!addresses.contains(&program_address)); - addresses.push(program_address); - } - } - } - - #[test] - fn test_find_program_address() { - for _ in 0..1_000 { - let program_id = Pubkey::new_unique(); - let (address, bump_seed) = - Pubkey::find_program_address(&[b"Lil'", b"Bits"], &program_id); - assert_eq!( - address, - Pubkey::create_program_address(&[b"Lil'", b"Bits", &[bump_seed]], &program_id) - .unwrap() - ); - } - } - - fn pubkey_from_seed_by_marker(marker: &[u8]) -> Result { - let key = Pubkey::new_unique(); - let owner = Pubkey::default(); - - let mut to_fake = owner.to_bytes().to_vec(); - to_fake.extend_from_slice(marker); - - let seed = from_utf8(&to_fake[..to_fake.len() - 32]).expect("not utf8"); - let base = &Pubkey::try_from(&to_fake[to_fake.len() - 32..]).unwrap(); - - Pubkey::create_with_seed(&key, seed, base) - } - - #[test] - fn test_create_with_seed_rejects_illegal_owner() { - assert_eq!( - pubkey_from_seed_by_marker(PDA_MARKER), - Err(PubkeyError::IllegalOwner) - ); - assert!(pubkey_from_seed_by_marker(&PDA_MARKER[1..]).is_ok()); - } - - #[test] - fn test_pubkey_error_from_primitive_exhaustive() { - for variant in PubkeyError::iter() { - let variant_i64 = variant.clone() as i64; - assert_eq!( - PubkeyError::from_repr(variant_i64 as usize), - PubkeyError::from_i64(variant_i64) - ); - assert_eq!(PubkeyError::from(variant_i64 as u64), variant); - } - } - - #[test] - fn test_parse_pubkey_error_from_primitive_exhaustive() { - for variant in ParsePubkeyError::iter() { - let variant_i64 = variant as i64; - assert_eq!( - ParsePubkeyError::from_repr(variant_i64 as usize), - ParsePubkeyError::from_i64(variant_i64) - ); - } - } - - #[test] - fn test_pubkey_macro() { - const PK: Pubkey = Pubkey::from_str_const("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"); - assert_eq!(pubkey!("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq"), PK); - assert_eq!( - Pubkey::from_str("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq").unwrap(), - PK - ); - } - - #[test] - fn test_as_array() { - let bytes = [1u8; 32]; - let key = Pubkey::from(bytes); - assert_eq!(key.as_array(), &bytes); - assert_eq!(key.as_array(), &key.to_bytes()); - // Sanity check: ensure the pointer is the same. - assert_eq!(key.as_array().as_ptr(), key.0.as_ptr()); - } -} diff --git a/pubkey/src/syscalls.rs b/pubkey/src/syscalls.rs deleted file mode 100644 index 13baad1c0..000000000 --- a/pubkey/src/syscalls.rs +++ /dev/null @@ -1,4 +0,0 @@ -/// Syscall definitions used by `solana_pubkey`. -pub use solana_define_syscall::definitions::{ - sol_create_program_address, sol_log_pubkey, sol_try_find_program_address, -}; diff --git a/quic-definitions/Cargo.toml b/quic-definitions/Cargo.toml index e932aef59..8df3ff2b9 100644 --- a/quic-definitions/Cargo.toml +++ b/quic-definitions/Cargo.toml @@ -2,7 +2,8 @@ name = "solana-quic-definitions" description = "Definitions related to Solana over QUIC." documentation = "https://docs.rs/solana-quic-definitions" -version = "2.3.0" +version = "2.3.1" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/quic-definitions/src/lib.rs b/quic-definitions/src/lib.rs index 1ddbd1c1d..c8edb1876 100644 --- a/quic-definitions/src/lib.rs +++ b/quic-definitions/src/lib.rs @@ -22,9 +22,7 @@ pub const QUIC_MAX_TIMEOUT: Duration = Duration::from_secs(60); /// To avoid idle timeout, the QUIC endpoint sends a ping every /// QUIC_KEEP_ALIVE. This shouldn't be too low to avoid unnecessary ping traffic. -/// For upgrade purpose, we keep the original one. Once the network is upgraded -/// to the one having higher QUIC_MAX_TIMEOUT, this value can be increased. -pub const QUIC_KEEP_ALIVE: Duration = Duration::from_secs(1); +pub const QUIC_KEEP_ALIVE: Duration = Duration::from_secs(45); // Disable Quic send fairness. // When set to false, streams are still scheduled based on priority, @@ -58,5 +56,5 @@ pub const QUIC_MIN_STAKED_RECEIVE_WINDOW_RATIO: u64 = 128; pub const QUIC_MAX_STAKED_RECEIVE_WINDOW_RATIO: u64 = 512; pub trait NotifyKeyUpdate { - fn update_key(&self, key: &Keypair) -> Result<(), Box>; + fn update_key(&self, key: &Keypair) -> Result<(), Box>; } diff --git a/rent-debits/src/lib.rs b/rent-debits/src/lib.rs deleted file mode 100644 index d6f38d958..000000000 --- a/rent-debits/src/lib.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![cfg_attr(docsrs, feature(doc_auto_cfg))] -use { - solana_pubkey::Pubkey, - solana_reward_info::{RewardInfo, RewardType}, - std::collections::HashMap, -}; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct RentDebit { - rent_collected: u64, - post_balance: u64, -} - -impl RentDebit { - fn try_into_reward_info(self) -> Option { - let rent_debit = i64::try_from(self.rent_collected) - .ok() - .and_then(|r| r.checked_neg()); - rent_debit.map(|rent_debit| RewardInfo { - reward_type: RewardType::Rent, - lamports: rent_debit, - post_balance: self.post_balance, - commission: None, // Not applicable - }) - } -} - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct RentDebits(HashMap); -impl RentDebits { - pub fn get_account_rent_debit(&self, address: &Pubkey) -> u64 { - self.0 - .get(address) - .map(|r| r.rent_collected) - .unwrap_or_default() - } - - // These functions/fields are only usable from a dev context (i.e. tests and benches) - #[cfg(feature = "dev-context-only-utils")] - pub fn len(&self) -> usize { - self.0.len() - } - - #[cfg(feature = "dev-context-only-utils")] - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn insert(&mut self, address: &Pubkey, rent_collected: u64, post_balance: u64) { - if rent_collected != 0 { - self.0.insert( - *address, - RentDebit { - rent_collected, - post_balance, - }, - ); - } - } - - pub fn into_unordered_rewards_iter(self) -> impl Iterator { - self.0 - .into_iter() - .filter_map(|(address, rent_debit)| Some((address, rent_debit.try_into_reward_info()?))) - } -} diff --git a/reserved-account-keys/Cargo.toml b/reserved-account-keys/Cargo.toml deleted file mode 100644 index 9b31aea8d..000000000 --- a/reserved-account-keys/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "solana-reserved-account-keys" -description = "Reserved Solana account keys" -documentation = "https://docs.rs/solana-reserved-account-keys" -version = "2.2.2" -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -license = { workspace = true } -edition = { workspace = true } - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] -all-features = true -rustdoc-args = ["--cfg=docsrs"] - -[features] -frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"] - -[dependencies] -lazy_static = { workspace = true } -solana-feature-set = { workspace = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-frozen-abi-macro = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-pubkey = { workspace = true, default-features = false } -solana-sdk-ids = { workspace = true } - -[dev-dependencies] -solana-message = { workspace = true } -solana-sysvar = { workspace = true } - -[lints] -workspace = true diff --git a/reserved-account-keys/src/lib.rs b/reserved-account-keys/src/lib.rs deleted file mode 100644 index bc42a1272..000000000 --- a/reserved-account-keys/src/lib.rs +++ /dev/null @@ -1,263 +0,0 @@ -//! Collection of reserved account keys that cannot be write-locked by transactions. -//! New reserved account keys may be added as long as they specify a feature -//! gate that transitions the key into read-only at an epoch boundary. -#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![deprecated(since = "2.2.2", note = "Use agave-reserved-account-keys instead")] -#![allow(deprecated)] - -use { - lazy_static::lazy_static, - solana_feature_set::{self as feature_set, FeatureSet}, - solana_pubkey::Pubkey, - solana_sdk_ids::{ - address_lookup_table, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, - compute_budget, config, ed25519_program, feature, loader_v4, native_loader, - secp256k1_program, secp256r1_program, stake, system_program, sysvar, vote, - zk_elgamal_proof_program, zk_token_proof_program, - }, - std::collections::{HashMap, HashSet}, -}; - -// ReservedAccountKeys is not serialized into or deserialized from bank -// snapshots but the bank requires this trait to be implemented anyways. -#[cfg(feature = "frozen-abi")] -impl ::solana_frozen_abi::abi_example::AbiExample for ReservedAccountKeys { - fn example() -> Self { - // ReservedAccountKeys is not Serialize so just rely on Default. - ReservedAccountKeys::default() - } -} - -/// `ReservedAccountKeys` holds the set of currently active/inactive -/// account keys that are reserved by the protocol and may not be write-locked -/// during transaction processing. -#[derive(Debug, Clone, PartialEq)] -pub struct ReservedAccountKeys { - /// Set of currently active reserved account keys - pub active: HashSet, - /// Set of currently inactive reserved account keys that will be moved to the - /// active set when their feature id is activated - inactive: HashMap, -} - -impl Default for ReservedAccountKeys { - fn default() -> Self { - Self::new(&RESERVED_ACCOUNTS) - } -} - -impl ReservedAccountKeys { - /// Compute a set of active / inactive reserved account keys from a list of - /// keys with a designated feature id. If a reserved account key doesn't - /// designate a feature id, it's already activated and should be inserted - /// into the active set. If it does have a feature id, insert the key and - /// its feature id into the inactive map. - fn new(reserved_accounts: &[ReservedAccount]) -> Self { - Self { - active: reserved_accounts - .iter() - .filter(|reserved| reserved.feature_id.is_none()) - .map(|reserved| reserved.key) - .collect(), - inactive: reserved_accounts - .iter() - .filter_map(|ReservedAccount { key, feature_id }| { - feature_id.as_ref().map(|feature_id| (*key, *feature_id)) - }) - .collect(), - } - } - - /// Compute a set with all reserved keys active, regardless of whether their - /// feature was activated. This is not to be used by the runtime. Useful for - /// off-chain utilities that need to filter out reserved accounts. - pub fn new_all_activated() -> Self { - Self { - active: Self::all_keys_iter().copied().collect(), - inactive: HashMap::default(), - } - } - - /// Returns whether the specified key is reserved - pub fn is_reserved(&self, key: &Pubkey) -> bool { - self.active.contains(key) - } - - /// Move inactive reserved account keys to the active set if their feature - /// is active. - pub fn update_active_set(&mut self, feature_set: &FeatureSet) { - self.inactive.retain(|reserved_key, feature_id| { - if feature_set.is_active(feature_id) { - self.active.insert(*reserved_key); - false - } else { - true - } - }); - } - - /// Return an iterator over all active / inactive reserved keys. This is not - /// to be used by the runtime. Useful for off-chain utilities that need to - /// filter out reserved accounts. - pub fn all_keys_iter() -> impl Iterator { - RESERVED_ACCOUNTS - .iter() - .map(|reserved_key| &reserved_key.key) - } - - /// Return an empty set of reserved keys for visibility when using in - /// tests where the dynamic reserved key set is not available - pub fn empty_key_set() -> HashSet { - HashSet::default() - } -} - -/// `ReservedAccount` represents a reserved account that will not be -/// write-lockable by transactions. If a feature id is set, the account will -/// become read-only only after the feature has been activated. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -struct ReservedAccount { - key: Pubkey, - feature_id: Option, -} - -impl ReservedAccount { - fn new_pending(key: Pubkey, feature_id: Pubkey) -> Self { - Self { - key, - feature_id: Some(feature_id), - } - } - - fn new_active(key: Pubkey) -> Self { - Self { - key, - feature_id: None, - } - } -} - -// New reserved accounts should be added in alphabetical order and must specify -// a feature id for activation. Reserved accounts cannot be removed from this -// list without breaking consensus. -lazy_static! { - static ref RESERVED_ACCOUNTS: Vec = [ - // builtin programs - ReservedAccount::new_pending(address_lookup_table::id(), feature_set::add_new_reserved_account_keys::id()), - ReservedAccount::new_active(bpf_loader::id()), - ReservedAccount::new_active(bpf_loader_deprecated::id()), - ReservedAccount::new_active(bpf_loader_upgradeable::id()), - ReservedAccount::new_pending(compute_budget::id(), feature_set::add_new_reserved_account_keys::id()), - ReservedAccount::new_active(config::id()), - ReservedAccount::new_pending(ed25519_program::id(), feature_set::add_new_reserved_account_keys::id()), - ReservedAccount::new_active(feature::id()), - ReservedAccount::new_pending(loader_v4::id(), feature_set::add_new_reserved_account_keys::id()), - ReservedAccount::new_pending(secp256k1_program::id(), feature_set::add_new_reserved_account_keys::id()), - ReservedAccount::new_pending(secp256r1_program::id(), feature_set::enable_secp256r1_precompile::id()), - #[allow(deprecated)] - ReservedAccount::new_active(stake::config::id()), - ReservedAccount::new_active(stake::id()), - ReservedAccount::new_active(system_program::id()), - ReservedAccount::new_active(vote::id()), - ReservedAccount::new_pending(zk_elgamal_proof_program::id(), feature_set::add_new_reserved_account_keys::id()), - ReservedAccount::new_pending(zk_token_proof_program::id(), feature_set::add_new_reserved_account_keys::id()), - - // sysvars - ReservedAccount::new_active(sysvar::clock::id()), - ReservedAccount::new_pending(sysvar::epoch_rewards::id(), feature_set::add_new_reserved_account_keys::id()), - ReservedAccount::new_active(sysvar::epoch_schedule::id()), - #[allow(deprecated)] - ReservedAccount::new_active(sysvar::fees::id()), - ReservedAccount::new_active(sysvar::instructions::id()), - ReservedAccount::new_pending(sysvar::last_restart_slot::id(), feature_set::add_new_reserved_account_keys::id()), - #[allow(deprecated)] - ReservedAccount::new_active(sysvar::recent_blockhashes::id()), - ReservedAccount::new_active(sysvar::rent::id()), - ReservedAccount::new_active(sysvar::rewards::id()), - ReservedAccount::new_active(sysvar::slot_hashes::id()), - ReservedAccount::new_active(sysvar::slot_history::id()), - ReservedAccount::new_active(sysvar::stake_history::id()), - - // other - ReservedAccount::new_active(native_loader::id()), - ReservedAccount::new_pending(sysvar::id(), feature_set::add_new_reserved_account_keys::id()), - ].to_vec(); -} - -#[cfg(test)] -mod tests { - #![allow(deprecated)] - use {super::*, solana_message::legacy::BUILTIN_PROGRAMS_KEYS, solana_sysvar::ALL_IDS}; - - #[test] - fn test_is_reserved() { - let feature_id = Pubkey::new_unique(); - let active_reserved_account = ReservedAccount::new_active(Pubkey::new_unique()); - let pending_reserved_account = - ReservedAccount::new_pending(Pubkey::new_unique(), feature_id); - let reserved_account_keys = - ReservedAccountKeys::new(&[active_reserved_account, pending_reserved_account]); - - assert!( - reserved_account_keys.is_reserved(&active_reserved_account.key), - "active reserved accounts should be inserted into the active set" - ); - assert!( - !reserved_account_keys.is_reserved(&pending_reserved_account.key), - "pending reserved accounts should NOT be inserted into the active set" - ); - } - - #[test] - fn test_update_active_set() { - let feature_ids = [Pubkey::new_unique(), Pubkey::new_unique()]; - let active_reserved_key = Pubkey::new_unique(); - let pending_reserved_keys = [Pubkey::new_unique(), Pubkey::new_unique()]; - let reserved_accounts = vec![ - ReservedAccount::new_active(active_reserved_key), - ReservedAccount::new_pending(pending_reserved_keys[0], feature_ids[0]), - ReservedAccount::new_pending(pending_reserved_keys[1], feature_ids[1]), - ]; - - let mut reserved_account_keys = ReservedAccountKeys::new(&reserved_accounts); - assert!(reserved_account_keys.is_reserved(&active_reserved_key)); - assert!(!reserved_account_keys.is_reserved(&pending_reserved_keys[0])); - assert!(!reserved_account_keys.is_reserved(&pending_reserved_keys[1])); - - // Updating the active set with a default feature set should be a no-op - let previous_reserved_account_keys = reserved_account_keys.clone(); - let mut feature_set = FeatureSet::default(); - reserved_account_keys.update_active_set(&feature_set); - assert_eq!(reserved_account_keys, previous_reserved_account_keys); - - // Updating the active set with an activated feature should also activate - // the corresponding reserved key from inactive to active - feature_set.active.insert(feature_ids[0], 0); - reserved_account_keys.update_active_set(&feature_set); - - assert!(reserved_account_keys.is_reserved(&active_reserved_key)); - assert!(reserved_account_keys.is_reserved(&pending_reserved_keys[0])); - assert!(!reserved_account_keys.is_reserved(&pending_reserved_keys[1])); - - // Update the active set again to ensure that the inactive map is - // properly retained - feature_set.active.insert(feature_ids[1], 0); - reserved_account_keys.update_active_set(&feature_set); - - assert!(reserved_account_keys.is_reserved(&active_reserved_key)); - assert!(reserved_account_keys.is_reserved(&pending_reserved_keys[0])); - assert!(reserved_account_keys.is_reserved(&pending_reserved_keys[1])); - } - - #[test] - fn test_static_list_compat() { - let mut static_set = HashSet::new(); - static_set.extend(ALL_IDS.iter().cloned()); - static_set.extend(BUILTIN_PROGRAMS_KEYS.iter().cloned()); - - let initial_active_set = ReservedAccountKeys::default().active; - - assert_eq!(initial_active_set, static_set); - } -} diff --git a/reward-info/Cargo.toml b/reward-info/Cargo.toml index e3b55141b..a332d0260 100644 --- a/reward-info/Cargo.toml +++ b/reward-info/Cargo.toml @@ -13,7 +13,7 @@ edition = { workspace = true } targets = ["x86_64-unknown-linux-gnu"] [features] -frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"] +frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro", "serde"] serde = ["dep:serde", "dep:serde_derive"] [dependencies] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 00822fdf5..e88baf106 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.85.1" +channel = "1.88.0" diff --git a/sanitize/Cargo.toml b/sanitize/Cargo.toml index 0fa9524d3..db1c724e2 100644 --- a/sanitize/Cargo.toml +++ b/sanitize/Cargo.toml @@ -2,7 +2,8 @@ name = "solana-sanitize" description = "Solana Message Sanitization" documentation = "https://docs.rs/solana-sanitize" -version = "2.2.1" +rust-version = "1.81.0" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/sanitize/src/lib.rs b/sanitize/src/lib.rs index f0733f863..546bb9837 100644 --- a/sanitize/src/lib.rs +++ b/sanitize/src/lib.rs @@ -1,6 +1,6 @@ //! A trait for sanitizing values and members of over the wire messages. -use {core::fmt, std::error::Error}; +use core::{error::Error, fmt}; #[derive(PartialEq, Debug, Eq, Clone)] pub enum SanitizeError { diff --git a/scripts/build-sbf.sh b/scripts/build-sbf.sh index 700caea42..44cc87e9a 100755 --- a/scripts/build-sbf.sh +++ b/scripts/build-sbf.sh @@ -5,32 +5,28 @@ here="$(dirname "$0")" src_root="$(readlink -f "${here}/..")" cd "${src_root}" -exclude_list=( - ".github" - "scripts" - "client-traits" - "ed25519-program" - "example-mocks" - "feature-set" - "feature-set-interface" - "file-download" - "genesis-config" - "keypair" - "logger" - "offchain-message" - "precompiles" - "presigner" - "quic-definitions" - "rent-collector" - "reserved-account-keys" - "secp256k1-program" - "secp256r1-program" - "system-transaction" - "transaction" +build_sbf_excludes=( + --exclude solana-client-traits + --exclude solana-ed25519-program + --exclude solana-example-mocks + --exclude solana-file-download + --exclude solana-genesis-config + --exclude solana-keypair + --exclude solana-logger + --exclude solana-offchain-message + --exclude solana-presigner + --exclude solana-quic-definitions + --exclude solana-rent-collector + --exclude solana-sdk-wasm-js + --exclude solana-sdk-wasm-js-tests + --exclude solana-secp256k1-program + --exclude solana-secp256r1-program + --exclude solana-system-transaction + --exclude solana-transaction + --exclude solana-sdk ) -for dir in $(git ls-tree -d --name-only HEAD .); do - if [[ ! " ${exclude_list[*]} " =~ [[:space:]]${dir}[[:space:]] ]]; then - (cd "$dir" && RUSTFLAGS="-Dwarnings" cargo build-sbf) - fi -done +./cargo nightly hack --workspace "${build_sbf_excludes[@]}" build-sbf + +# This can be added back in once the SDK upgrades to v2.3 of Agave tools +#./cargo nightly build-sbf --manifest-path sdk/Cargo.toml --no-default-features diff --git a/scripts/check-doc.sh b/scripts/check-doc.sh index 004199e78..a5f661493 100755 --- a/scripts/check-doc.sh +++ b/scripts/check-doc.sh @@ -5,4 +5,5 @@ here="$(dirname "$0")" src_root="$(readlink -f "${here}/..")" cd "${src_root}" +export RUSTDOCFLAGS="-D warnings" ./cargo nightly hack doc --all-features diff --git a/scripts/check-nits.sh b/scripts/check-nits.sh index 0a5371ce0..55daeca00 100755 --- a/scripts/check-nits.sh +++ b/scripts/check-nits.sh @@ -17,10 +17,11 @@ declare prints=( # Parts of the tree that are expected to be print free declare print_free_tree=( ':**.rs' + ':^address/src/hasher.rs' + ':^address/src/syscalls.rs' ':^logger/src/lib.rs' ':^msg/src/lib.rs' ':^program-option/src/lib.rs' - ':^pubkey/src/lib.rs' ':^sysvar/src/program_stubs.rs' ':^**bin**.rs' ':^**bench**.rs' diff --git a/scripts/patch-crates-functions.sh b/scripts/patch-crates-functions.sh index a32162a98..d08a8f76b 100644 --- a/scripts/patch-crates-functions.sh +++ b/scripts/patch-crates-functions.sh @@ -13,6 +13,7 @@ crate_dirs=( big-mod-exp bincode blake3-hasher + bls-signatures bn254 borsh client-traits @@ -21,7 +22,6 @@ crate_dirs=( commitment-config compute-budget-interface cpi - decode-error define-syscall derivation-path ed25519-program @@ -29,9 +29,9 @@ crate_dirs=( epoch-rewards epoch-rewards-hasher epoch-schedule + epoch-stake example-mocks feature-gate-interface - feature-set fee-calculator fee-structure file-download @@ -61,7 +61,6 @@ crate_dirs=( packet poh-config precompile-error - precompiles presigner program program-entrypoint @@ -73,8 +72,6 @@ crate_dirs=( quic-definitions rent rent-collector - rent-debits - reserved-account-keys reward-info sanitize sdk @@ -93,6 +90,7 @@ crate_dirs=( shred-version signature signer + signer-store slot-hashes slot-history stable-layout diff --git a/scripts/rust-version.sh b/scripts/rust-version.sh index 90c6e682c..3662a50c6 100755 --- a/scripts/rust-version.sh +++ b/scripts/rust-version.sh @@ -38,7 +38,7 @@ fi if [[ -n $RUST_NIGHTLY_VERSION ]]; then nightly_version="$RUST_NIGHTLY_VERSION" else - nightly_version=2025-04-01 + nightly_version=2025-06-29 fi export rust_stable="$stable_version" diff --git a/scripts/test-bench.sh b/scripts/test-bench.sh index eccbccd2c..84af67809 100755 --- a/scripts/test-bench.sh +++ b/scripts/test-bench.sh @@ -5,4 +5,4 @@ here="$(dirname "$0")" src_root="$(readlink -f "${here}/..")" cd "${src_root}" -./cargo nightly bench -p solana-sdk --features openssl-vendored +./cargo nightly bench -p solana-sdk diff --git a/scripts/test-doc.sh b/scripts/test-doc.sh new file mode 100755 index 000000000..27c96edb7 --- /dev/null +++ b/scripts/test-doc.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -eo pipefail +here="$(dirname "$0")" +src_root="$(readlink -f "${here}/..")" +cd "${src_root}" + +./cargo nightly hack test --doc --all-features -- --nocapture diff --git a/scripts/test-wasm.sh b/scripts/test-wasm.sh index 12b224f86..77bc739b3 100755 --- a/scripts/test-wasm.sh +++ b/scripts/test-wasm.sh @@ -5,10 +5,14 @@ here="$(dirname "$0")" src_root="$(readlink -f "${here}/..")" cd "${src_root}" -for dir in program sdk ; do - ( - cd "$dir" - npm install - npm test - ) -done +( + cd sdk-wasm-js + npm install + npm test +) + +( + cd sdk-wasm-js-tests + npm install + npm test +) diff --git a/sdk-macro/Cargo.toml b/sdk-macro/Cargo.toml index 5b2b807d5..eecfd891d 100644 --- a/sdk-macro/Cargo.toml +++ b/sdk-macro/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-sdk-macro" description = "Solana SDK Macro" documentation = "https://docs.rs/solana-sdk-macro" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/sdk-macro/src/lib.rs b/sdk-macro/src/lib.rs index 13841b126..17918dca7 100644 --- a/sdk-macro/src/lib.rs +++ b/sdk-macro/src/lib.rs @@ -96,36 +96,6 @@ fn deprecated_id_to_tokens( }); } -struct SdkPubkey(proc_macro2::TokenStream); - -impl Parse for SdkPubkey { - fn parse(input: ParseStream) -> Result { - parse_id(input, quote! { ::solana_sdk::pubkey::Pubkey }).map(Self) - } -} - -impl ToTokens for SdkPubkey { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let id = &self.0; - tokens.extend(quote! {#id}) - } -} - -struct ProgramSdkPubkey(proc_macro2::TokenStream); - -impl Parse for ProgramSdkPubkey { - fn parse(input: ParseStream) -> Result { - parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) - } -} - -impl ToTokens for ProgramSdkPubkey { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let id = &self.0; - tokens.extend(quote! {#id}) - } -} - struct Id(proc_macro2::TokenStream); impl Parse for Id { @@ -154,46 +124,6 @@ impl ToTokens for IdDeprecated { } } -struct ProgramSdkId(proc_macro2::TokenStream); -impl Parse for ProgramSdkId { - fn parse(input: ParseStream) -> Result { - parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) - } -} - -impl ToTokens for ProgramSdkId { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - id_to_tokens(&self.0, quote! { ::solana_program::pubkey::Pubkey }, tokens) - } -} - -struct ProgramSdkIdDeprecated(proc_macro2::TokenStream); -impl Parse for ProgramSdkIdDeprecated { - fn parse(input: ParseStream) -> Result { - parse_id(input, quote! { ::solana_program::pubkey::Pubkey }).map(Self) - } -} - -impl ToTokens for ProgramSdkIdDeprecated { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - deprecated_id_to_tokens(&self.0, quote! { ::solana_program::pubkey::Pubkey }, tokens) - } -} - -#[deprecated(since = "2.1.0", note = "Use `solana_pubkey::pubkey` instead")] -#[proc_macro] -pub fn pubkey(input: TokenStream) -> TokenStream { - let id = parse_macro_input!(input as SdkPubkey); - TokenStream::from(quote! {#id}) -} - -#[deprecated(since = "2.1.0", note = "Use `solana_pubkey::pubkey!` instead")] -#[proc_macro] -pub fn program_pubkey(input: TokenStream) -> TokenStream { - let id = parse_macro_input!(input as ProgramSdkPubkey); - TokenStream::from(quote! {#id}) -} - #[proc_macro] pub fn declare_id(input: TokenStream) -> TokenStream { let id = parse_macro_input!(input as Id); @@ -206,23 +136,6 @@ pub fn declare_deprecated_id(input: TokenStream) -> TokenStream { TokenStream::from(quote! {#id}) } -#[deprecated(since = "2.1.0", note = "Use `solana_pubkey::declare_id` instead")] -#[proc_macro] -pub fn program_declare_id(input: TokenStream) -> TokenStream { - let id = parse_macro_input!(input as ProgramSdkId); - TokenStream::from(quote! {#id}) -} - -#[deprecated( - since = "2.1.0", - note = "Use `solana_pubkey::declare_deprecated_id` instead" -)] -#[proc_macro] -pub fn program_declare_deprecated_id(input: TokenStream) -> TokenStream { - let id = parse_macro_input!(input as ProgramSdkIdDeprecated); - TokenStream::from(quote! {#id}) -} - fn parse_pubkey( id_literal: &LitStr, pubkey_type: &proc_macro2::TokenStream, diff --git a/program/.gitignore b/sdk-wasm-js-tests/.gitignore similarity index 100% rename from program/.gitignore rename to sdk-wasm-js-tests/.gitignore diff --git a/sdk-wasm-js-tests/Cargo.toml b/sdk-wasm-js-tests/Cargo.toml new file mode 100644 index 000000000..b5828977b --- /dev/null +++ b/sdk-wasm-js-tests/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "solana-sdk-wasm-js-tests" +description = "Tests for using the Solana SDK Wasm JS crate" +documentation = "https://docs.rs/solana-system-interface-wasm-js" +publish = false +version = "1.0.0" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +solana-address = { workspace = true } +solana-instruction = { workspace = true, features = ["std"] } +solana-sdk-wasm-js = { workspace = true } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +js-sys = { workspace = true } +wasm-bindgen = { workspace = true } + +[lints] +workspace = true diff --git a/sdk-wasm-js-tests/package.json b/sdk-wasm-js-tests/package.json new file mode 120000 index 000000000..83802bbe1 --- /dev/null +++ b/sdk-wasm-js-tests/package.json @@ -0,0 +1 @@ +../sdk-wasm-js/package.json \ No newline at end of file diff --git a/sdk-wasm-js-tests/src/lib.rs b/sdk-wasm-js-tests/src/lib.rs new file mode 100644 index 000000000..1d5f72afb --- /dev/null +++ b/sdk-wasm-js-tests/src/lib.rs @@ -0,0 +1,27 @@ +//! `SystemInstruction` Javascript interface +#![cfg(target_arch = "wasm32")] +#![allow(non_snake_case)] +pub use solana_sdk_wasm_js::{ + address::Address, hash::Hash, instruction::Instruction, keypair::Keypair, solana_program_init, + transaction::Transaction, +}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct MyProgramInstruction; + +fn my_program_instruction(program_id: &solana_address::Address) -> solana_instruction::Instruction { + solana_instruction::Instruction { + program_id: *program_id, + accounts: vec![], + data: vec![], + } +} + +#[wasm_bindgen] +impl MyProgramInstruction { + #[wasm_bindgen(constructor)] + pub fn constructor(program_id: &Address) -> Instruction { + my_program_instruction(program_id).into() + } +} diff --git a/sdk-wasm-js-tests/tests/transaction.mjs b/sdk-wasm-js-tests/tests/transaction.mjs new file mode 100644 index 000000000..db37d9b92 --- /dev/null +++ b/sdk-wasm-js-tests/tests/transaction.mjs @@ -0,0 +1,42 @@ +import { expect } from "chai"; +import { + solana_program_init, + Address, + Keypair, + Hash, + MyProgramInstruction, + Transaction, +} from "crate"; +solana_program_init(); + +describe("Transaction", function () { + it("Instruction", () => { + const payer = Keypair.fromBytes( + new Uint8Array([ + 241, 230, 222, 64, 184, 48, 232, 92, 156, 210, 229, 183, 154, 251, 5, + 227, 98, 184, 34, 234, 39, 106, 62, 210, 166, 187, 31, 44, 40, 96, 24, + 51, 252, 28, 2, 120, 234, 212, 139, 111, 96, 8, 168, 204, 34, 72, 199, + 205, 117, 165, 82, 51, 32, 93, 211, 36, 239, 245, 139, 218, 99, 211, + 207, 177, + ]) + ); + + const programId = new Address("11111111111111111111111111111111"); + const recentBlockhash = new Hash( + "EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k" + ); + + let instructions = []; + let instruction = new MyProgramInstruction(programId); + instructions.push(instruction); + + let transaction = new Transaction(instructions, payer.pubkey()); + transaction.partialSign(payer, recentBlockhash); + expect(transaction.isSigned()).to.be.true; + transaction.verify(); + + expect(Buffer.from(transaction.toBytes()).toString("base64")).to.equal( + "AfvLzMtWBl2MvGFOE6rPZ6gjzKv7eVlNXF0wO4VDxjFXZx0AA/x05cmRHJZR8InwR4lBEwVsHSVa/uBwYSh0dQEBAAEC/BwCeOrUi29gCKjMIkjHzXWlUjMgXdMk7/WL2mPTz7EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMSa53YDeCBU8Xqd7OpDtETroO2xLG8dMcbg5KhL8FLrAQEAAA==" + ); + }); +}); diff --git a/sdk-wasm-js/.gitignore b/sdk-wasm-js/.gitignore new file mode 100644 index 000000000..936e5c57a --- /dev/null +++ b/sdk-wasm-js/.gitignore @@ -0,0 +1,2 @@ +/node_modules/ +/package-lock.json diff --git a/sdk-wasm-js/Cargo.toml b/sdk-wasm-js/Cargo.toml new file mode 100644 index 000000000..2f4ea3b66 --- /dev/null +++ b/sdk-wasm-js/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "solana-sdk-wasm-js" +description = "Solana SDK Wasm JS" +documentation = "https://docs.rs/solana-sdk-wasm-js" +version = "1.0.0" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[package.metadata.docs.rs] +targets = ["wasm32-unknown-unknown"] +all-features = true +rustdoc-args = ["--cfg=docsrs"] + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +bincode = { workspace = true } +solana-address = { workspace = true, features = ["curve25519", "sha2", "std"] } +solana-hash = { workspace = true } +solana-instruction = { workspace = true, features = ["std"] } +solana-keypair = { workspace = true } +solana-message = { workspace = true } +solana-signature = { workspace = true } +solana-signer = { workspace = true } +solana-transaction = { workspace = true, features = ["bincode", "verify"] } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +console_error_panic_hook = { workspace = true } +console_log = { workspace = true } +getrandom = { workspace = true, features = ["js"] } +js-sys = { workspace = true } +log = { workspace = true } +wasm-bindgen = { workspace = true } + +[lints] +workspace = true diff --git a/sdk-wasm-js/README.md b/sdk-wasm-js/README.md new file mode 100644 index 000000000..7d6f12cc1 --- /dev/null +++ b/sdk-wasm-js/README.md @@ -0,0 +1,15 @@ +

+ + Solana + +

+ +# Solana SDK WASM JS + +Use the Solana SDK WASM JS crate to build a JS package with `wasm-pack` usable in Node or browser environments. +See the [Solana Program Crate](https://crates.io/crates/solana-program) instead for on-chain programs, and, the [Solana SDK Crate](https://crates.io/crates/solana-sdk) for client-side +applications. + +More information about Solana is available in the [Solana documentation](https://solana.com/docs). + +Still have questions? Ask us on [Stack Exchange](https://sola.na/sse) diff --git a/program/package.json b/sdk-wasm-js/package.json similarity index 100% rename from program/package.json rename to sdk-wasm-js/package.json diff --git a/sdk-wasm-js/src/address.rs b/sdk-wasm-js/src/address.rs new file mode 100644 index 000000000..7c96449af --- /dev/null +++ b/sdk-wasm-js/src/address.rs @@ -0,0 +1,142 @@ +//! Address wrapper + +use { + crate::display_to_jsvalue, + js_sys::{Array, Uint8Array}, + wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}, +}; + +#[wasm_bindgen] +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Address { + pub(crate) inner: solana_address::Address, +} + +crate::conversion::impl_inner_conversion!(Address, solana_address::Address); + +fn js_value_to_seeds_vec(array_of_uint8_arrays: &[JsValue]) -> Result>, JsValue> { + let vec_vec_u8 = array_of_uint8_arrays + .iter() + .filter_map(|u8_array| { + u8_array + .dyn_ref::() + .map(|u8_array| u8_array.to_vec()) + }) + .collect::>(); + + if vec_vec_u8.len() != array_of_uint8_arrays.len() { + Err("Invalid Array of Uint8Arrays".into()) + } else { + Ok(vec_vec_u8) + } +} + +#[allow(non_snake_case)] +#[wasm_bindgen] +impl Address { + /// Create a new Address object + /// + /// * `value` - optional public key as a base58 encoded string, `Uint8Array`, `[number]` + #[wasm_bindgen(constructor)] + pub fn constructor(value: JsValue) -> Result { + if let Some(base58_str) = value.as_string() { + base58_str + .parse::() + .map(Into::into) + .map_err(display_to_jsvalue) + } else if let Some(uint8_array) = value.dyn_ref::() { + solana_address::Address::try_from(uint8_array.to_vec()) + .map(Into::into) + .map_err(|err| JsValue::from(std::format!("Invalid Uint8Array address: {err:?}"))) + } else if let Some(array) = value.dyn_ref::() { + let mut bytes = std::vec![]; + let iterator = js_sys::try_iter(&array.values())?.expect("array to be iterable"); + for x in iterator { + let x = x?; + + if let Some(n) = x.as_f64() { + if n >= 0. && n <= 255. { + bytes.push(n as u8); + continue; + } + } + return Err(std::format!("Invalid array argument: {:?}", x).into()); + } + solana_address::Address::try_from(bytes) + .map(Into::into) + .map_err(|err| JsValue::from(std::format!("Invalid Array address: {err:?}"))) + } else if value.is_undefined() { + Ok(solana_address::Address::default().into()) + } else { + Err("Unsupported argument".into()) + } + } + + /// Return the base58 string representation of the public key + pub fn toString(&self) -> std::string::String { + std::string::ToString::to_string(&self.inner) + } + + /// Check if a `Address` is on the ed25519 curve. + pub fn isOnCurve(&self) -> bool { + self.inner.is_on_curve() + } + + /// Checks if two `Address`s are equal + pub fn equals(&self, other: &Self) -> bool { + self.inner == other.inner + } + + /// Return the `Uint8Array` representation of the public key + pub fn toBytes(&self) -> std::boxed::Box<[u8]> { + self.inner.to_bytes().into() + } + + /// Derive an Address from anothern Address, string seed, and a program id + pub fn createWithSeed(base: &Self, seed: &str, owner: &Self) -> Result { + solana_address::Address::create_with_seed(&base.inner, seed, &owner.inner) + .map(Into::into) + .map_err(display_to_jsvalue) + } + + /// Derive a program address from seeds and a program id + pub fn createProgramAddress( + seeds: std::boxed::Box<[JsValue]>, + program_id: &Self, + ) -> Result { + let seeds_vec = js_value_to_seeds_vec(&seeds)?; + let seeds_slice = seeds_vec + .iter() + .map(|seed| seed.as_slice()) + .collect::>(); + + solana_address::Address::create_program_address(seeds_slice.as_slice(), &program_id.inner) + .map(Into::into) + .map_err(display_to_jsvalue) + } + + /// Find a valid program address + /// + /// Returns: + /// * `[Address, number]` - the program address and bump seed + pub fn findProgramAddress( + seeds: std::boxed::Box<[JsValue]>, + program_id: &Self, + ) -> Result { + let seeds_vec = js_value_to_seeds_vec(&seeds)?; + let seeds_slice = seeds_vec + .iter() + .map(|seed| seed.as_slice()) + .collect::>(); + + let (address, bump_seed) = solana_address::Address::find_program_address( + seeds_slice.as_slice(), + &program_id.inner, + ); + + let result = Array::new_with_length(2); + result.set(0, Address::from(address).into()); + result.set(1, bump_seed.into()); + Ok(result.into()) + } +} diff --git a/sdk-wasm-js/src/hash.rs b/sdk-wasm-js/src/hash.rs new file mode 100644 index 000000000..d617d2d0b --- /dev/null +++ b/sdk-wasm-js/src/hash.rs @@ -0,0 +1,73 @@ +//! Wrapper over `solana_hash::Hash` with wasm-bindgen +use { + js_sys::{Array, Uint8Array}, + std::{boxed::Box, format, string::String, vec}, + wasm_bindgen::{prelude::*, JsCast}, +}; + +#[wasm_bindgen] +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Hash { + pub(crate) inner: solana_hash::Hash, +} + +crate::conversion::impl_inner_conversion!(Hash, solana_hash::Hash); + +#[allow(non_snake_case)] +#[wasm_bindgen] +impl Hash { + /// Create a new Hash object + /// + /// * `value` - optional hash as a base58 encoded string, `Uint8Array`, `[number]` + #[wasm_bindgen(constructor)] + pub fn constructor(value: JsValue) -> Result { + if let Some(base58_str) = value.as_string() { + base58_str + .parse::() + .map(Into::into) + .map_err(|x| JsValue::from(x.to_string())) + } else if let Some(uint8_array) = value.dyn_ref::() { + <[u8; solana_hash::HASH_BYTES]>::try_from(uint8_array.to_vec()) + .map(solana_hash::Hash::new_from_array) + .map(Into::into) + .map_err(|err| format!("Invalid Hash value: {err:?}").into()) + } else if let Some(array) = value.dyn_ref::() { + let mut bytes = vec![]; + let iterator = js_sys::try_iter(&array.values())?.expect("array to be iterable"); + for x in iterator { + let x = x?; + + if let Some(n) = x.as_f64() { + if n >= 0. && n <= 255. { + bytes.push(n as u8); + continue; + } + } + return Err(format!("Invalid array argument: {:?}", x).into()); + } + <[u8; solana_hash::HASH_BYTES]>::try_from(bytes) + .map(solana_hash::Hash::new_from_array) + .map(Into::into) + .map_err(|err| format!("Invalid Hash value: {err:?}").into()) + } else if value.is_undefined() { + Ok(solana_hash::Hash::default().into()) + } else { + Err("Unsupported argument".into()) + } + } + + /// Return the base58 string representation of the hash + pub fn toString(&self) -> String { + self.inner.to_string() + } + + /// Checks if two `Hash`s are equal + pub fn equals(&self, other: &Self) -> bool { + self.inner == other.inner + } + + /// Return the `Uint8Array` representation of the hash + pub fn toBytes(&self) -> Box<[u8]> { + self.inner.to_bytes().into() + } +} diff --git a/sdk-wasm-js/src/instruction.rs b/sdk-wasm-js/src/instruction.rs new file mode 100644 index 000000000..d321b5843 --- /dev/null +++ b/sdk-wasm-js/src/instruction.rs @@ -0,0 +1,56 @@ +//! The `Instructions` struct is a legacy workaround +//! from when wasm-bindgen lacked Vec support +//! (ref: https://github.com/rustwasm/wasm-bindgen/issues/111) +#![allow(non_snake_case)] + +use {crate::address::Address, wasm_bindgen::prelude::*}; + +/// wasm-bindgen version of the Instruction struct. +/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671 +/// is fixed. This must not diverge from the regular non-wasm Instruction struct. +#[wasm_bindgen] +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Instruction { + pub(crate) inner: solana_instruction::Instruction, +} + +crate::conversion::impl_inner_conversion!(Instruction, solana_instruction::Instruction); + +#[wasm_bindgen] +impl Instruction { + /// Create a new `Instruction` + #[wasm_bindgen(constructor)] + pub fn constructor(program_id: Address) -> Self { + solana_instruction::Instruction::new_with_bytes(program_id.inner, &[], std::vec::Vec::new()) + .into() + } + + pub fn setData(&mut self, data: &[u8]) { + self.inner.data = data.to_vec(); + } + + pub fn addAccount(&mut self, account_meta: AccountMeta) { + self.inner.accounts.push(account_meta.inner); + } +} + +#[wasm_bindgen] +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct AccountMeta { + pub(crate) inner: solana_instruction::AccountMeta, +} + +crate::conversion::impl_inner_conversion!(AccountMeta, solana_instruction::AccountMeta); + +#[wasm_bindgen] +impl AccountMeta { + /// Create a new writable `AccountMeta` + pub fn newWritable(address: Address, is_signer: bool) -> Self { + solana_instruction::AccountMeta::new(address.inner, is_signer).into() + } + + /// Create a new readonly `AccountMeta` + pub fn newReadonly(address: Address, is_signer: bool) -> Self { + solana_instruction::AccountMeta::new_readonly(address.inner, is_signer).into() + } +} diff --git a/sdk-wasm-js/src/keypair.rs b/sdk-wasm-js/src/keypair.rs new file mode 100644 index 000000000..cfb91dd7c --- /dev/null +++ b/sdk-wasm-js/src/keypair.rs @@ -0,0 +1,37 @@ +use {crate::address::Address, solana_signer::Signer, wasm_bindgen::prelude::*}; + +#[wasm_bindgen] +#[derive(Debug)] +pub struct Keypair { + pub(crate) inner: solana_keypair::Keypair, +} + +crate::conversion::impl_inner_conversion!(Keypair, solana_keypair::Keypair); + +#[allow(non_snake_case)] +#[wasm_bindgen] +impl Keypair { + /// Create a new `Keypair ` + #[wasm_bindgen(constructor)] + pub fn constructor() -> Self { + solana_keypair::Keypair::new().into() + } + + /// Convert a `Keypair` to a `Uint8Array` + pub fn toBytes(&self) -> Box<[u8]> { + self.inner.to_bytes().into() + } + + /// Recover a `Keypair` from a `Uint8Array` + pub fn fromBytes(bytes: &[u8]) -> Result { + solana_keypair::Keypair::try_from(bytes) + .map(Into::into) + .map_err(|e| e.to_string().into()) + } + + /// Return the `Address` for this `Keypair` + #[wasm_bindgen(js_name = pubkey)] + pub fn js_pubkey(&self) -> Address { + self.inner.pubkey().into() + } +} diff --git a/sdk-wasm-js/src/lib.rs b/sdk-wasm-js/src/lib.rs new file mode 100644 index 000000000..bc89f46d8 --- /dev/null +++ b/sdk-wasm-js/src/lib.rs @@ -0,0 +1,51 @@ +//! solana-program Javascript interface +#![cfg(target_arch = "wasm32")] + +use { + log::Level, + wasm_bindgen::prelude::{wasm_bindgen, JsValue}, +}; + +pub mod address; +pub mod hash; +pub mod instruction; +pub mod keypair; +pub mod message; +pub mod transaction; + +/// Initialize Javascript logging and panic handler +#[wasm_bindgen] +pub fn solana_program_init() { + use std::sync::Once; + static INIT: Once = Once::new(); + + INIT.call_once(|| { + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + console_log::init_with_level(Level::Info).unwrap(); + }); +} + +pub fn display_to_jsvalue(display: T) -> JsValue { + display.to_string().into() +} + +/// Simple macro for implementing conversion functions between wrapper types and +/// wrapped types. +mod conversion { + macro_rules! impl_inner_conversion { + ($Wrapper:ty, $Inner:ty) => { + impl From<$Inner> for $Wrapper { + fn from(inner: $Inner) -> Self { + Self { inner } + } + } + impl std::ops::Deref for $Wrapper { + type Target = $Inner; + fn deref(&self) -> &Self::Target { + &self.inner + } + } + }; + } + pub(crate) use impl_inner_conversion; +} diff --git a/sdk-wasm-js/src/message.rs b/sdk-wasm-js/src/message.rs new file mode 100644 index 000000000..793d8a8c6 --- /dev/null +++ b/sdk-wasm-js/src/message.rs @@ -0,0 +1,9 @@ +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +#[derive(Default, Debug, PartialEq, Eq, Clone)] +pub struct Message { + pub(crate) inner: solana_message::Message, +} + +crate::conversion::impl_inner_conversion!(Message, solana_message::Message); diff --git a/sdk-wasm-js/src/transaction.rs b/sdk-wasm-js/src/transaction.rs new file mode 100644 index 000000000..6e7333f58 --- /dev/null +++ b/sdk-wasm-js/src/transaction.rs @@ -0,0 +1,74 @@ +//! `Transaction` Javascript interface +#![allow(non_snake_case)] +use { + crate::{ + address::Address, hash::Hash, instruction::Instruction, keypair::Keypair, message::Message, + }, + wasm_bindgen::prelude::{wasm_bindgen, JsValue}, +}; + +/// wasm-bindgen version of the Transaction struct. +/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671 +/// is fixed. This must not diverge from the regular non-wasm Transaction struct. +#[wasm_bindgen] +#[derive(Debug, PartialEq, Default, Eq, Clone)] +pub struct Transaction { + pub(crate) inner: solana_transaction::Transaction, +} + +crate::conversion::impl_inner_conversion!(Transaction, solana_transaction::Transaction); + +#[wasm_bindgen] +impl Transaction { + /// Create a new `Transaction` + #[wasm_bindgen(constructor)] + pub fn constructor(instructions: Vec, payer: Option
) -> Self { + let instructions = instructions + .into_iter() + .map(|x| x.inner) + .collect::>(); + solana_transaction::Transaction::new_with_payer( + &instructions, + payer.map(|x| x.inner).as_ref(), + ) + .into() + } + + /// Return a message containing all data that should be signed. + #[wasm_bindgen(js_name = message)] + pub fn js_message(&self) -> Message { + self.inner.message.clone().into() + } + + /// Return the serialized message data to sign. + pub fn messageData(&self) -> Box<[u8]> { + self.inner.message_data().into() + } + + /// Verify the transaction + #[wasm_bindgen(js_name = verify)] + pub fn js_verify(&self) -> Result<(), JsValue> { + self.inner + .verify() + .map_err(|x| std::string::ToString::to_string(&x).into()) + } + + pub fn partialSign(&mut self, keypair: &Keypair, recent_blockhash: &Hash) { + self.inner + .partial_sign(&[&keypair.inner], recent_blockhash.inner); + } + + pub fn isSigned(&self) -> bool { + self.inner.is_signed() + } + + pub fn toBytes(&self) -> Box<[u8]> { + bincode::serialize(&self.inner).unwrap().into() + } + + pub fn fromBytes(bytes: &[u8]) -> Result { + bincode::deserialize::(bytes) + .map(Into::into) + .map_err(|x| std::string::ToString::to_string(&x).into()) + } +} diff --git a/program/tests/pubkey.mjs b/sdk-wasm-js/tests/address.mjs similarity index 62% rename from program/tests/pubkey.mjs rename to sdk-wasm-js/tests/address.mjs index 342273360..061156535 100644 --- a/program/tests/pubkey.mjs +++ b/sdk-wasm-js/tests/address.mjs @@ -1,60 +1,60 @@ import { expect } from "chai"; -import { solana_program_init, Pubkey } from "crate"; +import { solana_program_init, Address } from "crate"; solana_program_init(); // TODO: wasm_bindgen doesn't currently support exporting constants const MAX_SEED_LEN = 32; -describe("Pubkey", function () { +describe("Address", function () { it("invalid", () => { expect(() => { - new Pubkey([ + new Address([ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); }).to.throw(); expect(() => { - new Pubkey([ + new Address([ 'invalid', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); }).to.throw(); expect(() => { - new Pubkey( + new Address( "0x300000000000000000000000000000000000000000000000000000000000000000000" ); }).to.throw(); expect(() => { - new Pubkey( + new Address( "0x300000000000000000000000000000000000000000000000000000000000000" ); }).to.throw(); expect(() => { - new Pubkey( + new Address( "135693854574979916511997248057056142015550763280047535983739356259273198796800000" ); }).to.throw(); expect(() => { - new Pubkey("12345"); + new Address("12345"); }).to.throw(); }); it("toString", () => { - const key = new Pubkey("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"); + const key = new Address("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"); expect(key.toString()).to.eq("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"); - const key2 = new Pubkey("1111111111111111111111111111BukQL"); + const key2 = new Address("1111111111111111111111111111BukQL"); expect(key2.toString()).to.eq("1111111111111111111111111111BukQL"); - const key3 = new Pubkey("11111111111111111111111111111111"); + const key3 = new Address("11111111111111111111111111111111"); expect(key3.toString()).to.eq("11111111111111111111111111111111"); - const key4 = new Pubkey([ + const key4 = new Address([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); @@ -62,7 +62,7 @@ describe("Pubkey", function () { }); it("toBytes", () => { - const key = new Pubkey("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"); + const key = new Address("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"); expect(key.toBytes()).to.deep.equal( new Uint8Array([ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -70,7 +70,7 @@ describe("Pubkey", function () { ]) ); - const key2 = new Pubkey(); + const key2 = new Address(); expect(key2.toBytes()).to.deep.equal( new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -80,26 +80,26 @@ describe("Pubkey", function () { }); it("isOnCurve", () => { - let onCurve = new Pubkey("J4NYrSRccTUGXP7wmFwiByakqWKZb5RwpiAoskpgAQRb"); + let onCurve = new Address("J4NYrSRccTUGXP7wmFwiByakqWKZb5RwpiAoskpgAQRb"); expect(onCurve.isOnCurve()).to.be.true; - let offCurve = new Pubkey("12rqwuEgBYiGhBrDJStCiqEtzQpTTiZbh7teNVLuYcFA"); + let offCurve = new Address("12rqwuEgBYiGhBrDJStCiqEtzQpTTiZbh7teNVLuYcFA"); expect(offCurve.isOnCurve()).to.be.false; }); it("equals", () => { - const arrayKey = new Pubkey([ + const arrayKey = new Address([ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); - const base58Key = new Pubkey("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"); + const base58Key = new Address("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3"); expect(arrayKey.equals(base58Key)).to.be.true; }); it("createWithSeed", async () => { - const defaultPublicKey = new Pubkey("11111111111111111111111111111111"); - const derivedKey = Pubkey.createWithSeed( + const defaultPublicKey = new Address("11111111111111111111111111111111"); + const derivedKey = Address.createWithSeed( defaultPublicKey, "limber chicken: 4/45", defaultPublicKey @@ -107,75 +107,75 @@ describe("Pubkey", function () { expect( derivedKey.equals( - new Pubkey("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq") + new Address("9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq") ) ).to.be.true; }); it("createProgramAddress", async () => { - const programId = new Pubkey("BPFLoader1111111111111111111111111111111111"); - const publicKey = new Pubkey("SeedPubey1111111111111111111111111111111111"); + const programId = new Address("BPFLoader1111111111111111111111111111111111"); + const publicKey = new Address("SeedPubey1111111111111111111111111111111111"); - let programAddress = Pubkey.createProgramAddress( + let programAddress = Address.createProgramAddress( [Buffer.from("", "utf8"), Buffer.from([1])], programId ); expect( programAddress.equals( - new Pubkey("3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT") + new Address("3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT") ) ).to.be.true; - programAddress = Pubkey.createProgramAddress( + programAddress = Address.createProgramAddress( [Buffer.from("☉", "utf8")], programId ); expect( programAddress.equals( - new Pubkey("7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7") + new Address("7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7") ) ).to.be.true; - programAddress = Pubkey.createProgramAddress( + programAddress = Address.createProgramAddress( [Buffer.from("Talking", "utf8"), Buffer.from("Squirrels", "utf8")], programId ); expect( programAddress.equals( - new Pubkey("HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds") + new Address("HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds") ) ).to.be.true; - programAddress = Pubkey.createProgramAddress( + programAddress = Address.createProgramAddress( [publicKey.toBytes()], programId ); expect( programAddress.equals( - new Pubkey("GUs5qLUfsEHkcMB9T38vjr18ypEhRuNWiePW2LoK4E3K") + new Address("GUs5qLUfsEHkcMB9T38vjr18ypEhRuNWiePW2LoK4E3K") ) ).to.be.true; - const programAddress2 = Pubkey.createProgramAddress( + const programAddress2 = Address.createProgramAddress( [Buffer.from("Talking", "utf8")], programId ); expect(programAddress.equals(programAddress2)).to.eq(false); expect(() => { - Pubkey.createProgramAddress([Buffer.alloc(MAX_SEED_LEN + 1)], programId); + Address.createProgramAddress([Buffer.alloc(MAX_SEED_LEN + 1)], programId); }).to.throw(); }); it("findProgramAddress", async () => { - const programId = new Pubkey("BPFLoader1111111111111111111111111111111111"); - let [programAddress, nonce] = Pubkey.findProgramAddress( + const programId = new Address("BPFLoader1111111111111111111111111111111111"); + let [programAddress, nonce] = Address.findProgramAddress( [Buffer.from("", "utf8")], programId ); expect( programAddress.equals( - Pubkey.createProgramAddress( + Address.createProgramAddress( [Buffer.from("", "utf8"), Buffer.from([nonce])], programId ) diff --git a/program/tests/hash.mjs b/sdk-wasm-js/tests/hash.mjs similarity index 100% rename from program/tests/hash.mjs rename to sdk-wasm-js/tests/hash.mjs diff --git a/sdk/tests/keypair.mjs b/sdk-wasm-js/tests/keypair.mjs similarity index 100% rename from sdk/tests/keypair.mjs rename to sdk-wasm-js/tests/keypair.mjs diff --git a/sdk/tests/transaction.mjs b/sdk-wasm-js/tests/transaction.mjs similarity index 70% rename from sdk/tests/transaction.mjs rename to sdk-wasm-js/tests/transaction.mjs index 74c806d78..b06e98db5 100644 --- a/sdk/tests/transaction.mjs +++ b/sdk-wasm-js/tests/transaction.mjs @@ -1,17 +1,17 @@ import { expect } from "chai"; import { solana_program_init, - Pubkey, + AccountMeta, + Address, Keypair, Hash, - SystemInstruction, - Instructions, + Instruction, Transaction, } from "crate"; solana_program_init(); describe("Transaction", function () { - it("SystemInstruction::Transfer", () => { + it("Instruction", () => { const payer = Keypair.fromBytes( new Uint8Array([ 241, 230, 222, 64, 184, 48, 232, 92, 156, 210, 229, 183, 154, 251, 5, @@ -32,20 +32,24 @@ describe("Transaction", function () { ]) ); - const dst = new Pubkey("11111111111111111111111111111112"); + const programId = new Address("11111111111111111111111111111111"); + const dst = new Address("11111111111111111111111111111112"); + const instructionData = new Uint8Array([2, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0]); - const recent_blockhash = new Hash( + const recentBlockhash = new Hash( "EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k" ); - let instructions = new Instructions(); - instructions.push( - SystemInstruction.transfer(src.pubkey(), dst, BigInt(123)) - ); + let instructions = []; + let instruction = new Instruction(programId); + instruction.setData(instructionData); + instruction.addAccount(AccountMeta.newWritable(src.pubkey(), true)) + instruction.addAccount(AccountMeta.newWritable(dst, false)) + instructions.push(instruction); let transaction = new Transaction(instructions, payer.pubkey()); - transaction.partialSign(payer, recent_blockhash); - transaction.partialSign(src, recent_blockhash); + transaction.partialSign(payer, recentBlockhash); + transaction.partialSign(src, recentBlockhash); expect(transaction.isSigned()).to.be.true; transaction.verify(); diff --git a/sdk/.gitignore b/sdk/.gitignore index 14bd5d170..7809eb37b 100644 --- a/sdk/.gitignore +++ b/sdk/.gitignore @@ -1,4 +1,2 @@ /farf/ -/node_modules/ -/package-lock.json /target/ diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index a6359b979..26555517a 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -12,148 +12,71 @@ edition = { workspace = true } include = ["src/**/*", "README.md"] [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +targets = ["x86_64-unknown-linux-gnu"] all-features = true rustdoc-args = ["--cfg=docsrs"] [lib] -crate-type = ["cdylib", "rlib"] +crate-type = ["rlib"] [features] -# "program" feature is a legacy feature retained to support v1.3 and older -# programs. New development should not use this feature. Instead use the -# solana-program crate -program = [] - default = [ "borsh", "full", # functionality that is not compatible or needed for on-chain programs ] full = [ - "serde_json", "solana-signature", - "solana-transaction-context/debug-signature", "solana-pubkey/rand", - "dep:solana-client-traits", - "dep:solana-cluster-type", - "dep:solana-ed25519-program", - "dep:solana-commitment-config", - "dep:solana-compute-budget-interface", - "dep:solana-genesis-config", - "dep:solana-hard-forks", "dep:solana-keypair", "dep:solana-offchain-message", - "dep:solana-precompile-error", - "dep:solana-precompiles", "dep:solana-presigner", - "dep:solana-quic-definitions", - "dep:solana-rent-collector", - "dep:solana-secp256k1-program", "dep:solana-seed-derivable", "dep:solana-seed-phrase", "dep:solana-shred-version", "dep:solana-signer", - "dep:solana-system-transaction", "dep:solana-transaction", "dep:solana-transaction-error", ] -borsh = [ - "solana-compute-budget-interface/borsh", - "solana-program/borsh", - "solana-secp256k1-recover/borsh", -] +borsh = ["solana-program/borsh"] dev-context-only-utils = [ "solana-account/dev-context-only-utils", - "solana-compute-budget-interface/dev-context-only-utils", - "solana-rent-debits/dev-context-only-utils", + "solana-program/dev-context-only-utils", "solana-transaction/dev-context-only-utils", - "solana-transaction-context/dev-context-only-utils", ] frozen-abi = [ - "solana-feature-set/frozen-abi", "solana-fee-structure/frozen-abi", "solana-account/frozen-abi", - "solana-cluster-type/frozen-abi", - "solana-genesis-config/frozen-abi", - "solana-hard-forks/frozen-abi", "solana-inflation/frozen-abi", - "solana-packet/frozen-abi", - "solana-poh-config/frozen-abi", "solana-program/frozen-abi", - "solana-rent-collector/frozen-abi", - "solana-reward-info/frozen-abi", "solana-short-vec/frozen-abi", "solana-signature/frozen-abi", "solana-transaction/frozen-abi", "solana-transaction-error/frozen-abi", ] -# Enables the "vendored" feature of openssl inside of secp256r1-program -openssl-vendored = ["solana-precompiles/openssl-vendored"] [dependencies] bincode = { workspace = true } bs58 = { workspace = true } serde = { workspace = true } -serde_json = { workspace = true, optional = true } solana-account = { workspace = true, features = ["bincode"] } -solana-bn254 = { workspace = true } -solana-client-traits = { workspace = true, optional = true } -solana-cluster-type = { workspace = true, features = [ - "serde", -], optional = true } -solana-commitment-config = { workspace = true, optional = true, features = [ - "serde", -] } -solana-compute-budget-interface = { workspace = true, optional = true, features = [ - "serde", -] } -solana-decode-error = { workspace = true } -solana-derivation-path = { workspace = true } -solana-ed25519-program = { workspace = true, optional = true } solana-epoch-info = { workspace = true, features = ["serde"] } solana-epoch-rewards-hasher = { workspace = true } -solana-feature-set = { workspace = true } solana-fee-structure = { workspace = true, features = ["serde"] } -solana-genesis-config = { workspace = true, features = [ - "serde" -], optional = true } -solana-hard-forks = { workspace = true, features = [ - "serde", -], optional = true } solana-inflation = { workspace = true, features = ["serde"] } -solana-instruction = { workspace = true } solana-keypair = { workspace = true, optional = true, features = [ "seed-derivable", ] } solana-message = { workspace = true, features = ["serde"] } -solana-native-token = { workspace = true } -solana-nonce-account = { workspace = true } solana-offchain-message = { workspace = true, optional = true, features = ["verify"] } -solana-packet = { workspace = true, features = ["bincode", "serde"] } -solana-poh-config = { workspace = true, features = ["serde"] } -solana-precompile-error = { workspace = true, optional = true } -solana-precompiles = { workspace = true, optional = true } solana-presigner = { workspace = true, optional = true } solana-program = { workspace = true } solana-program-memory = { workspace = true } solana-pubkey = { workspace = true, default-features = false, features = [ "std", ] } -solana-quic-definitions = { workspace = true, optional = true } -solana-rent-collector = { workspace = true, features = [ - "serde" -], optional = true } -solana-rent-debits = { workspace = true } -solana-reserved-account-keys = { workspace = true } -solana-reward-info = { workspace = true, features = ["serde"] } solana-sanitize = { workspace = true } solana-sdk-ids = { workspace = true } solana-sdk-macro = { workspace = true } -solana-secp256k1-program = { workspace = true, optional = true, features = [ - "bincode", -] } -solana-secp256k1-recover = { workspace = true } -solana-secp256r1-program = { workspace = true, default-features = false } solana-seed-derivable = { workspace = true, optional = true } solana-seed-phrase = { workspace = true, optional = true } solana-serde = { workspace = true } @@ -167,34 +90,18 @@ solana-signature = { workspace = true, features = [ "verify", ], optional = true } solana-signer = { workspace = true, optional = true } -solana-system-transaction = { workspace = true, optional = true } solana-time-utils = { workspace = true } solana-transaction = { workspace = true, features = [ "blake3", - "precompiles", "serde", "verify" ], optional = true } -solana-transaction-context = { workspace = true, features = ["bincode"] } solana-transaction-error = { workspace = true, features = [ "serde", ], optional = true } -solana-validator-exit = { workspace = true } thiserror = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.1.1", features = ["wasm-bindgen"] } -js-sys = { workspace = true } -wasm-bindgen = { workspace = true } - [dev-dependencies] -curve25519-dalek = { workspace = true } -ed25519-dalek = { workspace = true } -libsecp256k1 = { workspace = true, features = ["hmac"] } -openssl = { workspace = true } -rand0-7 = { workspace = true } -serde_derive = { workspace = true } -serde_with = { workspace = true, features = ["macros"] } solana-instructions-sysvar = { workspace = true, features = ["dev-context-only-utils"] } solana-program = { workspace = true, features = ["dev-context-only-utils"] } solana-sdk = { path = ".", features = ["dev-context-only-utils"] } diff --git a/sdk/benches/big_mod_exp.rs b/sdk/benches/big_mod_exp.rs deleted file mode 100644 index 9649916e2..000000000 --- a/sdk/benches/big_mod_exp.rs +++ /dev/null @@ -1,1886 +0,0 @@ -#![feature(test)] - -extern crate test; -use {solana_sdk::big_mod_exp::big_mod_exp, test::Bencher}; - -#[bench] -fn bench_big_num_exponentiation_exp_3_mod_0512_bits_odd(b: &mut Bencher) { - let exponent = [3]; - - // a random base - let base = [ - 243, 125, 228, 56, 107, 91, 133, 57, 46, 184, 164, 236, 176, 173, 36, 149, 58, 238, 150, - 32, 181, 248, 42, 134, 92, 170, 70, 16, 109, 212, 16, 28, 195, 174, 187, 226, 140, 22, 3, - 31, 96, 234, 110, 254, 106, 215, 101, 164, 190, 88, 14, 112, 151, 78, 205, 151, 254, 225, - 153, 125, 109, 4, 68, 87, - ]; - - // a random modulus - let modulus = [ - 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, - 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, - 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, - 65, 85, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_3_mod_1024_bits_odd(b: &mut Bencher) { - let exponent = [3]; - - // a random base - let base = [ - 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, - 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, - 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, - 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, - 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, - 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, - 177, 196, 122, 75, 212, 7, 183, 80, 240, 66, - ]; - // a random modulus - let modulus = [ - 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, - 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, - 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, - 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, - 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, - 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, - 122, 82, 62, 74, 173, 42, 233, 38, 13, 241, - ]; - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_3_mod_2048_bits_odd(b: &mut Bencher) { - let exponent = [3]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 39, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_3_mod_4096_bits_odd(b: &mut Bencher) { - let exponent = [3]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 217, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_3_mod_0512_bits_even(b: &mut Bencher) { - let exponent = [3]; - - // a random base - let base = [ - 243, 125, 228, 56, 107, 91, 133, 57, 46, 184, 164, 236, 176, 173, 36, 149, 58, 238, 150, - 32, 181, 248, 42, 134, 92, 170, 70, 16, 109, 212, 16, 28, 195, 174, 187, 226, 140, 22, 3, - 31, 96, 234, 110, 254, 106, 215, 101, 164, 190, 88, 14, 112, 151, 78, 205, 151, 254, 225, - 153, 125, 109, 4, 68, 87, - ]; - - // a random modulus - let modulus = [ - 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, - 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, - 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, - 65, 86, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_3_mod_1024_bits_even(b: &mut Bencher) { - let exponent = [3]; - - // a random base - let base = [ - 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, - 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, - 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, - 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, - 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, - 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, - 177, 196, 122, 75, 212, 7, 183, 80, 240, 66, - ]; - // a random modulus - let modulus = [ - 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, - 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, - 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, - 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, - 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, - 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, - 122, 82, 62, 74, 173, 42, 233, 38, 13, 242, - ]; - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_3_mod_2048_bits_even(b: &mut Bencher) { - let exponent = [3]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 40, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_3_mod_4096_bits_even(b: &mut Bencher) { - let exponent = [3]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 218, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_65537_mod_0512_bits_odd(b: &mut Bencher) { - let exponent = [1, 0, 1]; - - // a random base - let base = [ - 243, 125, 228, 56, 107, 91, 133, 57, 46, 184, 164, 236, 176, 173, 36, 149, 58, 238, 150, - 32, 181, 248, 42, 134, 92, 170, 70, 16, 109, 212, 16, 28, 195, 174, 187, 226, 140, 22, 3, - 31, 96, 234, 110, 254, 106, 215, 101, 164, 190, 88, 14, 112, 151, 78, 205, 151, 254, 225, - 153, 125, 109, 4, 68, 87, - ]; - - // a random modulus - let modulus = [ - 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, - 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, - 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, - 65, 85, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_65537_mod_1024_bits_odd(b: &mut Bencher) { - let exponent = [1, 0, 1]; - - // a random base - let base = [ - 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, - 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, - 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, - 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, - 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, - 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, - 177, 196, 122, 75, 212, 7, 183, 80, 240, 66, - ]; - - // a random modulus - let modulus = [ - 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, - 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, - 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, - 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, - 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, - 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, - 122, 82, 62, 74, 173, 42, 233, 38, 13, 241, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_65537_mod_2048_bits_odd(b: &mut Bencher) { - let exponent = [1, 0, 1]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 39, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_65537_mod_4096_bits_odd(b: &mut Bencher) { - let exponent = [1, 0, 1]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 217, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_65537_mod_0512_bits_even(b: &mut Bencher) { - let exponent = [1, 0, 1]; - - // a random base - let base = [ - 243, 125, 228, 56, 107, 91, 133, 57, 46, 184, 164, 236, 176, 173, 36, 149, 58, 238, 150, - 32, 181, 248, 42, 134, 92, 170, 70, 16, 109, 212, 16, 28, 195, 174, 187, 226, 140, 22, 3, - 31, 96, 234, 110, 254, 106, 215, 101, 164, 190, 88, 14, 112, 151, 78, 205, 151, 254, 225, - 153, 125, 109, 4, 68, 87, - ]; - - // a random modulus - let modulus = [ - 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, - 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, - 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, - 65, 86, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_65537_mod_1024_bits_even(b: &mut Bencher) { - let exponent = [1, 0, 1]; - - // a random base - let base = [ - 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, - 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, - 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, - 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, - 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, - 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, - 177, 196, 122, 75, 212, 7, 183, 80, 240, 66, - ]; - - // a random modulus - let modulus = [ - 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, - 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, - 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, - 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, - 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, - 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, - 122, 82, 62, 74, 173, 42, 233, 38, 13, 242, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_65537_mod_2048_bits_even(b: &mut Bencher) { - let exponent = [1, 0, 1]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 40, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_65537_mod_4096_bits_even(b: &mut Bencher) { - let exponent = [1, 0, 1]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 218, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_0512_bits_mod_0512_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, - 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, - 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, - 32, 248, 119, - ]; - - // a random base - let base = [ - 243, 125, 228, 56, 107, 91, 133, 57, 46, 184, 164, 236, 176, 173, 36, 149, 58, 238, 150, - 32, 181, 248, 42, 134, 92, 170, 70, 16, 109, 212, 16, 28, 195, 174, 187, 226, 140, 22, 3, - 31, 96, 234, 110, 254, 106, 215, 101, 164, 190, 88, 14, 112, 151, 78, 205, 151, 254, 225, - 153, 125, 109, 4, 68, 87, - ]; - - // a random modulus - let modulus = [ - 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, - 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, - 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, - 65, 85, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_0512_bits_mod_1024_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, - 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, - 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, - 32, 248, 119, - ]; - - // a random base - let base = [ - 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, - 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, - 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, - 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, - 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, - 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, - 177, 196, 122, 75, 212, 7, 183, 80, 240, 66, - ]; - - // a random modulus - let modulus = [ - 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, - 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, - 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, - 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, - 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, - 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, - 122, 82, 62, 74, 173, 42, 233, 38, 13, 241, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_1024_bits_mod_1024_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 107, 92, 159, 59, 101, 117, 205, 228, 222, 58, 188, 58, 254, 101, 230, 53, 203, 200, 138, - 56, 160, 233, 81, 218, 113, 119, 10, 214, 68, 109, 113, 15, 146, 191, 225, 80, 22, 199, - 119, 236, 23, 159, 148, 40, 113, 28, 75, 45, 15, 54, 5, 64, 103, 55, 1, 220, 236, 41, 218, - 41, 93, 6, 3, 106, 235, 31, 22, 73, 243, 113, 171, 111, 20, 237, 200, 8, 99, 252, 202, 99, - 122, 242, 84, 180, 8, 58, 3, 129, 145, 62, 179, 78, 199, 35, 212, 16, 3, 55, 9, 197, 217, - 30, 42, 67, 220, 121, 193, 16, 15, 170, 116, 65, 157, 109, 34, 211, 41, 116, 161, 40, 77, - 223, 200, 240, 31, 17, 141, 189, - ]; - - // a random base - let base = [ - 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, - 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, - 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, - 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, - 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, - 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, - 177, 196, 122, 75, 212, 7, 183, 80, 240, 66, - ]; - - // a random modulus - let modulus = [ - 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, - 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, - 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, - 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, - 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, - 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, - 122, 82, 62, 74, 173, 42, 233, 38, 13, 241, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_0512_bits_mod_2048_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, - 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, - 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, - 32, 248, 119, - ]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 39, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_1024_bits_mod_2048_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 107, 92, 159, 59, 101, 117, 205, 228, 222, 58, 188, 58, 254, 101, 230, 53, 203, 200, 138, - 56, 160, 233, 81, 218, 113, 119, 10, 214, 68, 109, 113, 15, 146, 191, 225, 80, 22, 199, - 119, 236, 23, 159, 148, 40, 113, 28, 75, 45, 15, 54, 5, 64, 103, 55, 1, 220, 236, 41, 218, - 41, 93, 6, 3, 106, 235, 31, 22, 73, 243, 113, 171, 111, 20, 237, 200, 8, 99, 252, 202, 99, - 122, 242, 84, 180, 8, 58, 3, 129, 145, 62, 179, 78, 199, 35, 212, 16, 3, 55, 9, 197, 217, - 30, 42, 67, 220, 121, 193, 16, 15, 170, 116, 65, 157, 109, 34, 211, 41, 116, 161, 40, 77, - 223, 200, 240, 31, 17, 141, 189, - ]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 39, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_2048_bits_mod_2048_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 234, 85, 222, 102, 95, 165, 186, 221, 192, 109, 51, 204, 69, 225, 36, 118, 52, 132, 39, - 190, 10, 8, 82, 87, 149, 233, 35, 50, 36, 102, 243, 84, 50, 26, 54, 64, 38, 68, 154, 97, - 100, 221, 4, 81, 15, 47, 229, 100, 163, 68, 127, 163, 138, 24, 244, 125, 166, 116, 68, 126, - 201, 43, 192, 13, 236, 182, 213, 203, 235, 20, 2, 81, 168, 251, 87, 97, 69, 159, 138, 203, - 53, 43, 243, 14, 212, 5, 0, 229, 80, 72, 147, 130, 47, 13, 236, 180, 25, 100, 178, 148, - 171, 231, 252, 68, 57, 79, 14, 185, 155, 82, 103, 1, 98, 32, 204, 127, 242, 86, 25, 37, 19, - 240, 21, 64, 3, 160, 100, 76, 72, 220, 67, 123, 123, 139, 206, 75, 33, 177, 61, 129, 69, - 57, 186, 166, 3, 94, 162, 249, 22, 89, 245, 106, 180, 116, 222, 177, 231, 57, 73, 6, 217, - 252, 58, 212, 233, 219, 42, 144, 68, 92, 168, 147, 116, 82, 211, 224, 214, 156, 1, 52, 112, - 114, 193, 158, 137, 195, 46, 73, 179, 7, 229, 69, 151, 34, 78, 108, 138, 207, 37, 178, 41, - 142, 41, 163, 144, 206, 181, 71, 13, 195, 186, 74, 56, 93, 151, 97, 73, 57, 114, 198, 203, - 216, 182, 98, 88, 9, 68, 211, 235, 78, 105, 182, 245, 96, 5, 119, 229, 2, 50, 187, 159, - 131, 24, 4, 154, 234, 61, 95, 45, 102, 134, 106, 208, 39, 202, 165, - ]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 39, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_0512_bits_mod_4096_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, - 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, - 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, - 32, 248, 119, - ]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 217, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_1024_bits_mod_4096_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 107, 92, 159, 59, 101, 117, 205, 228, 222, 58, 188, 58, 254, 101, 230, 53, 203, 200, 138, - 56, 160, 233, 81, 218, 113, 119, 10, 214, 68, 109, 113, 15, 146, 191, 225, 80, 22, 199, - 119, 236, 23, 159, 148, 40, 113, 28, 75, 45, 15, 54, 5, 64, 103, 55, 1, 220, 236, 41, 218, - 41, 93, 6, 3, 106, 235, 31, 22, 73, 243, 113, 171, 111, 20, 237, 200, 8, 99, 252, 202, 99, - 122, 242, 84, 180, 8, 58, 3, 129, 145, 62, 179, 78, 199, 35, 212, 16, 3, 55, 9, 197, 217, - 30, 42, 67, 220, 121, 193, 16, 15, 170, 116, 65, 157, 109, 34, 211, 41, 116, 161, 40, 77, - 223, 200, 240, 31, 17, 141, 189, - ]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 217, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_2048_bits_mod_4096_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 234, 85, 222, 102, 95, 165, 186, 221, 192, 109, 51, 204, 69, 225, 36, 118, 52, 132, 39, - 190, 10, 8, 82, 87, 149, 233, 35, 50, 36, 102, 243, 84, 50, 26, 54, 64, 38, 68, 154, 97, - 100, 221, 4, 81, 15, 47, 229, 100, 163, 68, 127, 163, 138, 24, 244, 125, 166, 116, 68, 126, - 201, 43, 192, 13, 236, 182, 213, 203, 235, 20, 2, 81, 168, 251, 87, 97, 69, 159, 138, 203, - 53, 43, 243, 14, 212, 5, 0, 229, 80, 72, 147, 130, 47, 13, 236, 180, 25, 100, 178, 148, - 171, 231, 252, 68, 57, 79, 14, 185, 155, 82, 103, 1, 98, 32, 204, 127, 242, 86, 25, 37, 19, - 240, 21, 64, 3, 160, 100, 76, 72, 220, 67, 123, 123, 139, 206, 75, 33, 177, 61, 129, 69, - 57, 186, 166, 3, 94, 162, 249, 22, 89, 245, 106, 180, 116, 222, 177, 231, 57, 73, 6, 217, - 252, 58, 212, 233, 219, 42, 144, 68, 92, 168, 147, 116, 82, 211, 224, 214, 156, 1, 52, 112, - 114, 193, 158, 137, 195, 46, 73, 179, 7, 229, 69, 151, 34, 78, 108, 138, 207, 37, 178, 41, - 142, 41, 163, 144, 206, 181, 71, 13, 195, 186, 74, 56, 93, 151, 97, 73, 57, 114, 198, 203, - 216, 182, 98, 88, 9, 68, 211, 235, 78, 105, 182, 245, 96, 5, 119, 229, 2, 50, 187, 159, - 131, 24, 4, 154, 234, 61, 95, 45, 102, 134, 106, 208, 39, 202, 165, - ]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 217, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_4096_bits_mod_4096_bits_odd(b: &mut Bencher) { - // a random exponent - let exponent = [ - 160, 136, 220, 27, 39, 209, 128, 184, 213, 36, 207, 49, 210, 27, 221, 106, 122, 123, 158, - 77, 226, 64, 168, 133, 129, 82, 217, 239, 209, 235, 234, 153, 175, 4, 59, 165, 18, 109, 42, - 228, 194, 227, 131, 189, 98, 154, 242, 164, 206, 128, 151, 139, 167, 129, 179, 1, 31, 20, - 62, 168, 118, 232, 139, 241, 174, 171, 180, 238, 21, 190, 206, 250, 115, 99, 66, 152, 176, - 110, 213, 251, 176, 158, 145, 38, 61, 121, 183, 157, 18, 8, 202, 154, 26, 198, 32, 252, - 213, 40, 31, 241, 234, 13, 97, 166, 12, 199, 215, 205, 64, 121, 192, 240, 168, 241, 224, - 86, 157, 194, 1, 3, 135, 99, 201, 95, 185, 193, 142, 218, 122, 250, 84, 90, 150, 146, 2, - 173, 55, 255, 166, 150, 196, 182, 97, 4, 161, 85, 162, 74, 230, 138, 154, 128, 100, 161, - 62, 19, 74, 36, 249, 111, 45, 13, 236, 140, 73, 123, 174, 114, 45, 133, 124, 150, 15, 148, - 24, 192, 29, 116, 90, 51, 215, 62, 176, 177, 23, 211, 67, 97, 19, 231, 83, 147, 140, 99, - 186, 233, 213, 100, 109, 27, 124, 193, 193, 2, 212, 2, 55, 104, 122, 170, 249, 228, 183, - 109, 141, 58, 63, 232, 54, 255, 218, 109, 149, 174, 74, 157, 63, 252, 249, 149, 173, 28, - 249, 12, 39, 64, 90, 179, 81, 210, 129, 14, 247, 248, 169, 243, 182, 74, 143, 236, 217, - 255, 201, 184, 228, 67, 254, 115, 187, 93, 171, 34, 62, 182, 218, 0, 237, 66, 224, 51, 124, - 75, 28, 149, 207, 3, 41, 2, 113, 49, 2, 147, 227, 101, 82, 13, 120, 75, 4, 67, 244, 28, - 123, 32, 81, 32, 224, 63, 51, 62, 121, 8, 62, 234, 179, 181, 91, 76, 123, 183, 247, 135, - 40, 212, 170, 236, 45, 164, 17, 239, 65, 202, 175, 31, 116, 141, 219, 209, 253, 40, 231, - 175, 115, 59, 199, 88, 149, 101, 10, 29, 25, 233, 171, 62, 132, 90, 175, 237, 237, 167, - 153, 5, 114, 103, 227, 79, 128, 89, 207, 142, 215, 104, 92, 236, 98, 61, 187, 233, 145, - 119, 209, 100, 4, 146, 11, 247, 106, 123, 73, 200, 120, 121, 161, 118, 214, 69, 17, 66, 29, - 170, 255, 100, 59, 53, 107, 10, 231, 72, 103, 11, 223, 36, 14, 243, 252, 181, 247, 80, 253, - 110, 84, 106, 132, 102, 231, 136, 96, 148, 246, 185, 249, 207, 49, 205, 171, 168, 150, 84, - 146, 144, 228, 95, 164, 160, 194, 124, 69, 58, 168, 59, 101, 32, 196, 167, 87, 108, 99, - 126, 157, 244, 227, 224, 29, 105, 73, 249, 45, 109, 62, 180, 234, 251, 53, 11, 72, 116, 46, - 18, 102, 59, 160, 138, 22, 117, 161, 104, 189, 21, 193, 31, 175, 178, 131, 47, 127, 146, - 209, 129, 96, 61, 43, 238, 88, 211, 79, 157, 85, 15, 57, 82, 54, 104, 104, 201, 171, 60, - 26, 1, 137, 90, 234, 249, - ]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 217, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_0512_bits_mod_0512_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, - 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, - 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, - 32, 248, 119, - ]; - - // a random base - let base = [ - 243, 125, 228, 56, 107, 91, 133, 57, 46, 184, 164, 236, 176, 173, 36, 149, 58, 238, 150, - 32, 181, 248, 42, 134, 92, 170, 70, 16, 109, 212, 16, 28, 195, 174, 187, 226, 140, 22, 3, - 31, 96, 234, 110, 254, 106, 215, 101, 164, 190, 88, 14, 112, 151, 78, 205, 151, 254, 225, - 153, 125, 109, 4, 68, 87, - ]; - - // a random modulus - let modulus = [ - 249, 242, 76, 142, 109, 239, 3, 168, 130, 45, 156, 105, 209, 72, 218, 93, 86, 112, 88, 215, - 43, 194, 59, 35, 44, 86, 2, 252, 132, 113, 24, 4, 109, 98, 68, 209, 53, 191, 213, 162, 221, - 114, 213, 66, 58, 254, 152, 79, 82, 222, 79, 76, 1, 68, 255, 3, 218, 218, 83, 98, 85, 108, - 65, 86, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_0512_bits_mod_1024_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, - 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, - 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, - 32, 248, 119, - ]; - - // a random base - let base = [ - 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, - 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, - 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, - 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, - 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, - 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, - 177, 196, 122, 75, 212, 7, 183, 80, 240, 66, - ]; - - // a random modulus - let modulus = [ - 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, - 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, - 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, - 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, - 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, - 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, - 122, 82, 62, 74, 173, 42, 233, 38, 13, 242, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_1024_bits_mod_1024_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 107, 92, 159, 59, 101, 117, 205, 228, 222, 58, 188, 58, 254, 101, 230, 53, 203, 200, 138, - 56, 160, 233, 81, 218, 113, 119, 10, 214, 68, 109, 113, 15, 146, 191, 225, 80, 22, 199, - 119, 236, 23, 159, 148, 40, 113, 28, 75, 45, 15, 54, 5, 64, 103, 55, 1, 220, 236, 41, 218, - 41, 93, 6, 3, 106, 235, 31, 22, 73, 243, 113, 171, 111, 20, 237, 200, 8, 99, 252, 202, 99, - 122, 242, 84, 180, 8, 58, 3, 129, 145, 62, 179, 78, 199, 35, 212, 16, 3, 55, 9, 197, 217, - 30, 42, 67, 220, 121, 193, 16, 15, 170, 116, 65, 157, 109, 34, 211, 41, 116, 161, 40, 77, - 223, 200, 240, 31, 17, 141, 189, - ]; - - // a random base - let base = [ - 212, 177, 76, 117, 205, 210, 60, 63, 64, 203, 108, 135, 17, 114, 163, 95, 224, 106, 191, - 205, 112, 55, 118, 224, 234, 35, 97, 95, 254, 115, 29, 29, 155, 136, 100, 24, 208, 77, 141, - 136, 62, 201, 198, 76, 142, 13, 77, 111, 231, 196, 136, 198, 18, 7, 42, 155, 127, 177, 176, - 250, 30, 83, 243, 231, 197, 161, 33, 122, 254, 152, 1, 214, 70, 166, 155, 142, 77, 132, - 159, 158, 102, 62, 53, 226, 255, 64, 220, 68, 201, 221, 248, 237, 88, 135, 64, 229, 111, - 183, 2, 52, 48, 1, 45, 146, 26, 132, 64, 31, 77, 137, 131, 245, 191, 166, 68, 1, 216, 211, - 177, 196, 122, 75, 212, 7, 183, 80, 240, 66, - ]; - - // a random modulus - let modulus = [ - 237, 223, 117, 18, 201, 74, 224, 241, 183, 182, 90, 141, 137, 224, 33, 142, 133, 75, 192, - 99, 45, 75, 185, 134, 226, 65, 105, 202, 253, 125, 129, 38, 135, 120, 49, 248, 112, 4, 211, - 189, 0, 156, 21, 44, 227, 62, 38, 6, 32, 45, 254, 31, 108, 151, 172, 166, 18, 46, 3, 141, - 22, 176, 57, 160, 40, 104, 39, 68, 167, 233, 192, 157, 33, 200, 231, 220, 195, 161, 137, - 235, 28, 4, 117, 223, 173, 4, 38, 143, 50, 16, 254, 176, 146, 13, 195, 210, 247, 134, 71, - 226, 101, 7, 52, 150, 227, 221, 149, 152, 52, 84, 142, 243, 197, 230, 134, 182, 126, 183, - 122, 82, 62, 74, 173, 42, 233, 38, 13, 242, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_0512_bits_mod_2048_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, - 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, - 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, - 32, 248, 119, - ]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 40, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_1024_bits_mod_2048_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 107, 92, 159, 59, 101, 117, 205, 228, 222, 58, 188, 58, 254, 101, 230, 53, 203, 200, 138, - 56, 160, 233, 81, 218, 113, 119, 10, 214, 68, 109, 113, 15, 146, 191, 225, 80, 22, 199, - 119, 236, 23, 159, 148, 40, 113, 28, 75, 45, 15, 54, 5, 64, 103, 55, 1, 220, 236, 41, 218, - 41, 93, 6, 3, 106, 235, 31, 22, 73, 243, 113, 171, 111, 20, 237, 200, 8, 99, 252, 202, 99, - 122, 242, 84, 180, 8, 58, 3, 129, 145, 62, 179, 78, 199, 35, 212, 16, 3, 55, 9, 197, 217, - 30, 42, 67, 220, 121, 193, 16, 15, 170, 116, 65, 157, 109, 34, 211, 41, 116, 161, 40, 77, - 223, 200, 240, 31, 17, 141, 189, - ]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 40, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_2048_bits_mod_2048_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 234, 85, 222, 102, 95, 165, 186, 221, 192, 109, 51, 204, 69, 225, 36, 118, 52, 132, 39, - 190, 10, 8, 82, 87, 149, 233, 35, 50, 36, 102, 243, 84, 50, 26, 54, 64, 38, 68, 154, 97, - 100, 221, 4, 81, 15, 47, 229, 100, 163, 68, 127, 163, 138, 24, 244, 125, 166, 116, 68, 126, - 201, 43, 192, 13, 236, 182, 213, 203, 235, 20, 2, 81, 168, 251, 87, 97, 69, 159, 138, 203, - 53, 43, 243, 14, 212, 5, 0, 229, 80, 72, 147, 130, 47, 13, 236, 180, 25, 100, 178, 148, - 171, 231, 252, 68, 57, 79, 14, 185, 155, 82, 103, 1, 98, 32, 204, 127, 242, 86, 25, 37, 19, - 240, 21, 64, 3, 160, 100, 76, 72, 220, 67, 123, 123, 139, 206, 75, 33, 177, 61, 129, 69, - 57, 186, 166, 3, 94, 162, 249, 22, 89, 245, 106, 180, 116, 222, 177, 231, 57, 73, 6, 217, - 252, 58, 212, 233, 219, 42, 144, 68, 92, 168, 147, 116, 82, 211, 224, 214, 156, 1, 52, 112, - 114, 193, 158, 137, 195, 46, 73, 179, 7, 229, 69, 151, 34, 78, 108, 138, 207, 37, 178, 41, - 142, 41, 163, 144, 206, 181, 71, 13, 195, 186, 74, 56, 93, 151, 97, 73, 57, 114, 198, 203, - 216, 182, 98, 88, 9, 68, 211, 235, 78, 105, 182, 245, 96, 5, 119, 229, 2, 50, 187, 159, - 131, 24, 4, 154, 234, 61, 95, 45, 102, 134, 106, 208, 39, 202, 165, - ]; - - // a random base - let base = [ - 236, 66, 86, 50, 109, 186, 105, 32, 149, 81, 7, 31, 151, 116, 93, 59, 84, 247, 239, 100, - 174, 245, 37, 174, 204, 240, 52, 226, 252, 105, 16, 88, 180, 24, 90, 223, 60, 226, 147, - 165, 255, 74, 249, 183, 1, 80, 160, 48, 111, 90, 220, 16, 237, 217, 251, 30, 208, 24, 127, - 170, 237, 244, 15, 89, 205, 254, 128, 49, 245, 233, 139, 239, 4, 126, 248, 212, 173, 103, - 222, 225, 118, 93, 219, 91, 26, 90, 142, 91, 210, 149, 227, 222, 255, 227, 182, 233, 176, - 83, 210, 143, 174, 92, 46, 19, 242, 117, 6, 125, 163, 93, 116, 63, 71, 236, 139, 17, 192, - 239, 106, 133, 145, 158, 46, 238, 107, 80, 54, 80, 231, 138, 236, 44, 55, 13, 193, 159, - 144, 85, 138, 204, 84, 126, 66, 40, 104, 232, 113, 216, 165, 184, 198, 20, 234, 225, 170, - 174, 90, 101, 253, 231, 80, 252, 28, 148, 89, 64, 65, 26, 143, 60, 158, 116, 12, 14, 46, - 210, 99, 233, 187, 212, 44, 36, 47, 227, 123, 195, 45, 115, 12, 123, 16, 164, 92, 52, 229, - 65, 127, 114, 213, 116, 210, 2, 149, 144, 217, 131, 146, 67, 66, 91, 199, 46, 58, 5, 185, - 247, 73, 170, 6, 45, 109, 0, 191, 233, 95, 239, 241, 30, 61, 119, 54, 4, 164, 214, 202, - 251, 139, 28, 22, 219, 100, 233, 195, 151, 237, 183, 41, 153, 42, 82, 208, 222, 21, 160, - 100, 100, - ]; - - // a random modulus - let modulus = [ - 155, 66, 179, 54, 45, 180, 207, 15, 110, 66, 217, 170, 218, 229, 14, 147, 163, 227, 26, 27, - 56, 162, 176, 213, 136, 239, 229, 242, 214, 53, 97, 19, 91, 195, 133, 126, 130, 1, 54, 143, - 78, 210, 176, 236, 152, 95, 92, 140, 158, 72, 151, 225, 83, 120, 44, 192, 72, 12, 100, 19, - 76, 249, 175, 180, 3, 217, 241, 47, 99, 8, 101, 17, 7, 154, 235, 191, 239, 243, 156, 137, - 147, 6, 248, 70, 44, 52, 4, 159, 137, 14, 79, 178, 247, 112, 241, 56, 240, 45, 22, 250, 99, - 99, 79, 10, 147, 188, 219, 89, 129, 60, 204, 149, 6, 112, 52, 85, 204, 62, 164, 85, 59, - 200, 11, 239, 196, 157, 53, 128, 223, 221, 90, 234, 112, 74, 195, 52, 133, 189, 35, 110, - 66, 222, 150, 19, 121, 107, 23, 171, 46, 167, 10, 253, 119, 247, 214, 175, 239, 40, 45, 24, - 115, 2, 150, 243, 44, 187, 160, 142, 68, 56, 172, 77, 143, 142, 53, 216, 228, 216, 239, - 176, 186, 96, 11, 147, 160, 127, 107, 192, 246, 173, 95, 144, 190, 167, 93, 172, 81, 89, - 163, 86, 111, 48, 30, 172, 32, 33, 34, 224, 191, 214, 244, 161, 233, 222, 113, 112, 76, - 163, 71, 99, 138, 92, 127, 203, 253, 201, 164, 231, 61, 59, 98, 165, 238, 23, 196, 10, 177, - 253, 110, 149, 31, 57, 212, 43, 16, 24, 241, 163, 72, 81, 140, 115, 37, 155, 94, 40, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_0512_bits_mod_4096_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 30, 194, 86, 18, 177, 202, 203, 133, 7, 22, 133, 138, 102, 21, 107, 127, 141, 28, 166, 162, - 46, 101, 20, 119, 208, 32, 66, 141, 122, 70, 94, 79, 61, 251, 202, 97, 35, 129, 9, 73, 215, - 220, 88, 174, 113, 124, 103, 113, 254, 44, 96, 79, 250, 252, 33, 252, 12, 70, 43, 238, 90, - 32, 248, 119, - ]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 218, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_1024_bits_mod_4096_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 107, 92, 159, 59, 101, 117, 205, 228, 222, 58, 188, 58, 254, 101, 230, 53, 203, 200, 138, - 56, 160, 233, 81, 218, 113, 119, 10, 214, 68, 109, 113, 15, 146, 191, 225, 80, 22, 199, - 119, 236, 23, 159, 148, 40, 113, 28, 75, 45, 15, 54, 5, 64, 103, 55, 1, 220, 236, 41, 218, - 41, 93, 6, 3, 106, 235, 31, 22, 73, 243, 113, 171, 111, 20, 237, 200, 8, 99, 252, 202, 99, - 122, 242, 84, 180, 8, 58, 3, 129, 145, 62, 179, 78, 199, 35, 212, 16, 3, 55, 9, 197, 217, - 30, 42, 67, 220, 121, 193, 16, 15, 170, 116, 65, 157, 109, 34, 211, 41, 116, 161, 40, 77, - 223, 200, 240, 31, 17, 141, 189, - ]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 218, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_2048_bits_mod_4096_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 234, 85, 222, 102, 95, 165, 186, 221, 192, 109, 51, 204, 69, 225, 36, 118, 52, 132, 39, - 190, 10, 8, 82, 87, 149, 233, 35, 50, 36, 102, 243, 84, 50, 26, 54, 64, 38, 68, 154, 97, - 100, 221, 4, 81, 15, 47, 229, 100, 163, 68, 127, 163, 138, 24, 244, 125, 166, 116, 68, 126, - 201, 43, 192, 13, 236, 182, 213, 203, 235, 20, 2, 81, 168, 251, 87, 97, 69, 159, 138, 203, - 53, 43, 243, 14, 212, 5, 0, 229, 80, 72, 147, 130, 47, 13, 236, 180, 25, 100, 178, 148, - 171, 231, 252, 68, 57, 79, 14, 185, 155, 82, 103, 1, 98, 32, 204, 127, 242, 86, 25, 37, 19, - 240, 21, 64, 3, 160, 100, 76, 72, 220, 67, 123, 123, 139, 206, 75, 33, 177, 61, 129, 69, - 57, 186, 166, 3, 94, 162, 249, 22, 89, 245, 106, 180, 116, 222, 177, 231, 57, 73, 6, 217, - 252, 58, 212, 233, 219, 42, 144, 68, 92, 168, 147, 116, 82, 211, 224, 214, 156, 1, 52, 112, - 114, 193, 158, 137, 195, 46, 73, 179, 7, 229, 69, 151, 34, 78, 108, 138, 207, 37, 178, 41, - 142, 41, 163, 144, 206, 181, 71, 13, 195, 186, 74, 56, 93, 151, 97, 73, 57, 114, 198, 203, - 216, 182, 98, 88, 9, 68, 211, 235, 78, 105, 182, 245, 96, 5, 119, 229, 2, 50, 187, 159, - 131, 24, 4, 154, 234, 61, 95, 45, 102, 134, 106, 208, 39, 202, 165, - ]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 218, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} - -#[bench] -fn bench_big_num_exponentiation_exp_4096_bits_mod_4096_bits_even(b: &mut Bencher) { - // a random exponent - let exponent = [ - 160, 136, 220, 27, 39, 209, 128, 184, 213, 36, 207, 49, 210, 27, 221, 106, 122, 123, 158, - 77, 226, 64, 168, 133, 129, 82, 217, 239, 209, 235, 234, 153, 175, 4, 59, 165, 18, 109, 42, - 228, 194, 227, 131, 189, 98, 154, 242, 164, 206, 128, 151, 139, 167, 129, 179, 1, 31, 20, - 62, 168, 118, 232, 139, 241, 174, 171, 180, 238, 21, 190, 206, 250, 115, 99, 66, 152, 176, - 110, 213, 251, 176, 158, 145, 38, 61, 121, 183, 157, 18, 8, 202, 154, 26, 198, 32, 252, - 213, 40, 31, 241, 234, 13, 97, 166, 12, 199, 215, 205, 64, 121, 192, 240, 168, 241, 224, - 86, 157, 194, 1, 3, 135, 99, 201, 95, 185, 193, 142, 218, 122, 250, 84, 90, 150, 146, 2, - 173, 55, 255, 166, 150, 196, 182, 97, 4, 161, 85, 162, 74, 230, 138, 154, 128, 100, 161, - 62, 19, 74, 36, 249, 111, 45, 13, 236, 140, 73, 123, 174, 114, 45, 133, 124, 150, 15, 148, - 24, 192, 29, 116, 90, 51, 215, 62, 176, 177, 23, 211, 67, 97, 19, 231, 83, 147, 140, 99, - 186, 233, 213, 100, 109, 27, 124, 193, 193, 2, 212, 2, 55, 104, 122, 170, 249, 228, 183, - 109, 141, 58, 63, 232, 54, 255, 218, 109, 149, 174, 74, 157, 63, 252, 249, 149, 173, 28, - 249, 12, 39, 64, 90, 179, 81, 210, 129, 14, 247, 248, 169, 243, 182, 74, 143, 236, 217, - 255, 201, 184, 228, 67, 254, 115, 187, 93, 171, 34, 62, 182, 218, 0, 237, 66, 224, 51, 124, - 75, 28, 149, 207, 3, 41, 2, 113, 49, 2, 147, 227, 101, 82, 13, 120, 75, 4, 67, 244, 28, - 123, 32, 81, 32, 224, 63, 51, 62, 121, 8, 62, 234, 179, 181, 91, 76, 123, 183, 247, 135, - 40, 212, 170, 236, 45, 164, 17, 239, 65, 202, 175, 31, 116, 141, 219, 209, 253, 40, 231, - 175, 115, 59, 199, 88, 149, 101, 10, 29, 25, 233, 171, 62, 132, 90, 175, 237, 237, 167, - 153, 5, 114, 103, 227, 79, 128, 89, 207, 142, 215, 104, 92, 236, 98, 61, 187, 233, 145, - 119, 209, 100, 4, 146, 11, 247, 106, 123, 73, 200, 120, 121, 161, 118, 214, 69, 17, 66, 29, - 170, 255, 100, 59, 53, 107, 10, 231, 72, 103, 11, 223, 36, 14, 243, 252, 181, 247, 80, 253, - 110, 84, 106, 132, 102, 231, 136, 96, 148, 246, 185, 249, 207, 49, 205, 171, 168, 150, 84, - 146, 144, 228, 95, 164, 160, 194, 124, 69, 58, 168, 59, 101, 32, 196, 167, 87, 108, 99, - 126, 157, 244, 227, 224, 29, 105, 73, 249, 45, 109, 62, 180, 234, 251, 53, 11, 72, 116, 46, - 18, 102, 59, 160, 138, 22, 117, 161, 104, 189, 21, 193, 31, 175, 178, 131, 47, 127, 146, - 209, 129, 96, 61, 43, 238, 88, 211, 79, 157, 85, 15, 57, 82, 54, 104, 104, 201, 171, 60, - 26, 1, 137, 90, 234, 249, - ]; - - // a random base - let base = [ - 167, 62, 26, 222, 69, 55, 136, 13, 139, 152, 251, 52, 101, 99, 181, 160, 55, 137, 73, 135, - 48, 71, 232, 168, 183, 14, 161, 145, 163, 22, 31, 14, 111, 65, 93, 52, 253, 42, 115, 167, - 211, 27, 143, 95, 20, 20, 179, 231, 241, 169, 110, 220, 42, 178, 222, 110, 97, 186, 76, - 210, 43, 205, 210, 166, 58, 173, 28, 10, 192, 102, 35, 122, 240, 244, 186, 197, 211, 39, - 230, 59, 140, 42, 221, 90, 81, 107, 88, 210, 1, 222, 215, 116, 7, 190, 251, 226, 87, 131, - 53, 137, 108, 245, 194, 62, 173, 26, 124, 253, 192, 10, 143, 10, 56, 237, 191, 216, 13, 6, - 22, 37, 130, 226, 241, 58, 157, 230, 247, 125, 170, 124, 167, 184, 148, 204, 247, 5, 181, - 73, 81, 195, 64, 72, 33, 187, 100, 173, 35, 86, 99, 228, 124, 83, 64, 1, 176, 178, 194, - 236, 110, 202, 70, 204, 59, 147, 232, 246, 152, 93, 124, 222, 192, 136, 149, 14, 36, 225, - 122, 228, 16, 215, 49, 80, 30, 230, 235, 158, 29, 86, 209, 67, 172, 163, 79, 22, 167, 113, - 154, 5, 157, 187, 237, 144, 76, 77, 45, 177, 15, 21, 19, 7, 181, 125, 232, 9, 138, 111, - 163, 207, 196, 197, 162, 67, 66, 81, 36, 3, 68, 68, 36, 213, 243, 42, 41, 12, 173, 71, 197, - 51, 217, 122, 98, 142, 79, 177, 34, 6, 160, 189, 158, 248, 115, 238, 226, 10, 71, 179, 92, - 87, 14, 100, 13, 220, 105, 238, 238, 0, 229, 100, 96, 29, 18, 155, 53, 247, 10, 146, 252, - 2, 219, 96, 206, 225, 171, 59, 135, 177, 90, 174, 245, 3, 222, 95, 35, 1, 31, 107, 53, 99, - 117, 93, 207, 148, 62, 12, 140, 211, 0, 122, 39, 66, 21, 71, 197, 137, 97, 142, 240, 61, - 69, 25, 121, 165, 53, 40, 218, 248, 112, 213, 8, 91, 217, 236, 173, 227, 103, 250, 133, - 143, 0, 227, 117, 159, 69, 8, 52, 147, 0, 175, 255, 76, 129, 47, 230, 234, 58, 233, 128, 2, - 184, 190, 104, 241, 69, 95, 74, 176, 112, 75, 236, 81, 100, 222, 111, 171, 126, 16, 55, 26, - 1, 63, 15, 24, 147, 176, 50, 20, 23, 176, 176, 182, 72, 208, 105, 138, 160, 243, 113, 123, - 106, 145, 39, 176, 0, 192, 137, 187, 182, 9, 5, 16, 72, 2, 121, 54, 224, 231, 208, 116, - 144, 55, 134, 20, 235, 123, 80, 105, 37, 196, 166, 51, 26, 151, 84, 52, 120, 162, 194, 97, - 212, 242, 153, 205, 112, 158, 151, 244, 242, 79, 219, 128, 99, 246, 32, 38, 132, 34, 131, - 28, 117, 162, 68, 107, 21, 25, 68, 66, 203, 7, 179, 46, 119, 8, 31, 36, 239, 179, 140, 51, - 221, 151, 200, 68, 183, 132, 36, 171, 247, 80, 191, 125, 22, 210, 204, 83, 200, 103, 97, - 184, 61, 225, 127, 73, 104, 159, 172, 185, 202, 116, 154, 28, 150, 6, - ]; - - // a random modulus - let modulus = [ - 186, 147, 169, 139, 184, 41, 41, 80, 108, 1, 29, 237, 140, 15, 147, 98, 8, 192, 145, 125, - 112, 68, 139, 38, 31, 131, 18, 213, 128, 28, 239, 126, 50, 54, 178, 48, 110, 200, 255, 10, - 206, 143, 168, 51, 43, 18, 24, 80, 166, 137, 197, 251, 215, 163, 248, 230, 16, 81, 164, 40, - 118, 207, 12, 149, 30, 55, 8, 135, 56, 9, 118, 228, 18, 190, 224, 181, 78, 70, 141, 109, - 114, 123, 200, 223, 241, 143, 249, 55, 171, 184, 16, 113, 63, 95, 194, 141, 196, 90, 118, - 203, 194, 73, 229, 187, 126, 241, 137, 9, 58, 68, 205, 95, 6, 254, 191, 224, 240, 85, 254, - 200, 6, 210, 24, 1, 32, 131, 185, 210, 109, 71, 116, 58, 213, 187, 115, 210, 107, 65, 116, - 172, 131, 209, 45, 65, 144, 7, 82, 199, 187, 97, 202, 5, 47, 159, 80, 235, 221, 89, 102, - 236, 123, 243, 25, 133, 28, 19, 140, 117, 77, 214, 127, 208, 94, 18, 24, 166, 38, 101, 165, - 144, 183, 109, 78, 100, 128, 67, 215, 253, 248, 244, 242, 182, 219, 26, 135, 24, 192, 149, - 247, 65, 206, 203, 28, 66, 205, 95, 65, 190, 163, 68, 24, 142, 228, 152, 231, 136, 169, - 197, 37, 124, 201, 235, 127, 51, 7, 197, 221, 161, 243, 212, 204, 128, 76, 52, 58, 3, 60, - 158, 162, 140, 51, 233, 167, 231, 190, 227, 111, 82, 210, 48, 79, 232, 80, 202, 114, 161, - 230, 250, 197, 122, 65, 90, 91, 110, 7, 106, 55, 170, 156, 118, 133, 101, 248, 234, 156, - 106, 228, 193, 33, 74, 82, 188, 205, 42, 2, 187, 75, 213, 33, 67, 206, 15, 163, 25, 72, 32, - 192, 92, 239, 40, 15, 116, 155, 120, 213, 50, 142, 47, 161, 30, 44, 213, 100, 217, 213, - 159, 190, 230, 163, 63, 152, 119, 190, 42, 154, 81, 39, 70, 179, 101, 169, 74, 37, 143, 49, - 134, 99, 130, 101, 87, 111, 240, 38, 240, 164, 134, 162, 124, 109, 161, 181, 192, 42, 57, - 240, 133, 18, 215, 175, 164, 45, 150, 161, 30, 104, 217, 68, 3, 5, 57, 170, 148, 24, 116, - 96, 172, 23, 139, 23, 230, 127, 182, 178, 167, 100, 46, 182, 190, 176, 4, 245, 103, 158, - 50, 96, 24, 27, 107, 135, 46, 122, 17, 225, 183, 0, 58, 3, 243, 168, 84, 64, 34, 29, 39, - 17, 227, 240, 30, 150, 28, 76, 11, 86, 53, 143, 25, 164, 215, 164, 70, 71, 232, 195, 95, - 221, 117, 135, 3, 241, 40, 207, 123, 122, 148, 118, 56, 65, 218, 8, 88, 124, 219, 91, 236, - 194, 245, 37, 246, 54, 202, 36, 151, 160, 40, 75, 92, 175, 241, 161, 113, 53, 220, 67, 249, - 7, 118, 77, 214, 122, 148, 44, 164, 249, 239, 57, 102, 45, 136, 93, 4, 76, 51, 186, 156, - 101, 82, 217, 116, 211, 255, 92, 183, 101, 50, 73, 38, 79, 219, 63, 140, 174, 218, - ]; - - b.iter(|| { - big_mod_exp(&base, &exponent, &modulus); - }); -} diff --git a/sdk/package.json b/sdk/package.json deleted file mode 120000 index 763b62f88..000000000 --- a/sdk/package.json +++ /dev/null @@ -1 +0,0 @@ -../program/package.json \ No newline at end of file diff --git a/sdk/src/feature.rs b/sdk/src/feature.rs deleted file mode 100644 index 2224bec8d..000000000 --- a/sdk/src/feature.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[allow(deprecated)] -pub use solana_program::feature::*; diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index ef2e169f2..2cdb39bb8 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -34,15 +34,12 @@ // Allows macro expansion of `use ::solana_sdk::*` to work within this crate extern crate self as solana_sdk; -#[cfg(feature = "full")] -#[deprecated(since = "2.3.0", note = "Use `solana-commitment-config` crate instead")] -pub mod commitment_config { - pub use solana_commitment_config::*; -} +#[deprecated(since = "2.2.0", note = "Use `solana-message` crate instead")] +pub use solana_message as message; +#[cfg(feature = "borsh")] +pub use solana_program::borsh1; #[cfg(not(target_os = "solana"))] pub use solana_program::program_stubs; -#[cfg(target_arch = "wasm32")] -pub use solana_program::wasm_bindgen; pub use solana_program::{ account_info, big_mod_exp, blake3, bpf_loader, bpf_loader_deprecated, clock, config, custom_heap_default, custom_panic_default, debug_account_data, declare_deprecated_sysvar_id, @@ -51,147 +48,23 @@ pub use solana_program::{ program_error, program_option, program_pack, rent, secp256k1_program, serialize_utils, slot_hashes, slot_history, stable_layout, syscalls, sysvar, unchecked_div_by_const, }; -#[deprecated( - since = "2.3.0", - note = "Use `solana-address-lookup-table-interface` crate instead" -)] -pub mod address_lookup_table { - #[allow(deprecated)] - pub use solana_program::address_lookup_table::*; -} -#[deprecated( - since = "2.3.0", - note = "Use `solana-loader-v3-interface` crate instead" -)] -pub mod bpf_loader_upgradeable { - #[allow(deprecated)] - pub use solana_program::bpf_loader_upgradeable::*; -} -#[deprecated( - since = "2.3.0", - note = "Use `solana-loader-v2-interface` crate instead" -)] -pub mod loader_instruction { - #[allow(deprecated)] - pub use solana_program::loader_instruction::*; -} -#[deprecated( - since = "2.3.0", - note = "Use solana_loader_v3_interface::instruction instead" -)] -pub mod loader_upgradeable_instruction { - #[allow(deprecated)] - pub use solana_program::loader_upgradeable_instruction::*; -} -#[deprecated(since = "2.3.0", note = "Use solana-loader-v4-interface instead")] -pub mod loader_v4 { - #[allow(deprecated)] - pub use solana_program::loader_v4::*; -} -#[deprecated( - since = "2.3.0", - note = "Use solana_loader_v4_interface::instruction instead" -)] -pub mod loader_v4_instruction { - #[allow(deprecated)] - pub use solana_program::loader_v4_instruction::*; -} -#[deprecated(since = "2.2.0", note = "Use `solana-message` crate instead")] -pub use solana_message as message; -#[deprecated(since = "2.3.0", note = "Use `solana-nonce` crate instead")] -pub mod nonce { - #[allow(deprecated)] - pub use solana_program::nonce::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana-sdk-ids` crate instead")] -pub mod sdk_ids { - #[allow(deprecated)] - pub use solana_program::sdk_ids::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana-stake-interface` instead")] -pub mod stake { - #[allow(deprecated)] - pub use solana_program::stake::*; -} -#[deprecated( - since = "2.3.0", - note = "Use `solana_stake_interface::stake_history` instead" -)] -pub mod stake_history { - #[allow(deprecated)] - pub use solana_program::stake_history::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana_system_interface` crate instead")] -pub mod system_instruction { - #[allow(deprecated)] - pub use solana_program::system_instruction::*; -} -#[deprecated( - since = "2.3.0", - note = "Use `solana_system_interface::program` instead" -)] -pub mod system_program { - #[allow(deprecated)] - pub use solana_program::system_program::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana_vote_interface` crate instead")] -pub mod vote { - #[allow(deprecated)] - pub use solana_program::vote::*; -} -#[cfg(feature = "borsh")] -pub use solana_program::{borsh, borsh0_10, borsh1}; #[cfg(feature = "full")] #[deprecated(since = "2.2.0", note = "Use `solana-signer` crate instead")] pub use solana_signer::signers; pub mod entrypoint; pub mod entrypoint_deprecated; pub mod example_mocks; -#[deprecated( - since = "2.2.0", - note = "Use `solana-feature-gate-interface` crate instead" -)] -pub mod feature; -#[cfg(feature = "full")] -#[deprecated(since = "2.3.0", note = "Use `solana-genesis-config` crate instead")] -pub mod genesis_config { - pub use solana_genesis_config::*; -} -#[cfg(feature = "full")] -#[deprecated(since = "2.3.0", note = "Use `solana-hard-forks` crate instead")] -pub mod hard_forks { - pub use solana_hard_forks::*; -} pub mod hash; pub mod log; pub mod native_loader; -pub mod net; -#[deprecated(since = "2.2.2", note = "Use `agave-precompiles` crate instead")] -pub mod precompiles; -pub mod program_utils; pub mod pubkey; #[cfg(feature = "full")] -#[deprecated(since = "2.3.0", note = "Use `solana_rent_collector` crate instead")] -pub mod rent_collector { - pub use solana_rent_collector::*; -} -#[deprecated(since = "2.2.0", note = "Use `solana-reward-info` crate instead")] -pub mod reward_info { - pub use solana_reward_info::RewardInfo; -} -#[deprecated(since = "2.2.0", note = "Use `solana-reward-info` crate instead")] -pub mod reward_type { - pub use solana_reward_info::RewardType; -} -pub mod rpc_port; -#[cfg(feature = "full")] #[deprecated(since = "2.2.0", note = "Use `solana-shred-version` crate instead")] pub use solana_shred_version as shred_version; pub mod signature; pub mod signer; pub mod transaction; pub mod transport; -pub mod wasm; #[deprecated(since = "2.1.0", note = "Use `solana-account` crate instead")] pub use solana_account as account; @@ -200,36 +73,6 @@ pub use solana_account as account; note = "Use `solana_account::state_traits` crate instead" )] pub use solana_account::state_traits as account_utils; -#[deprecated(since = "2.3.0", note = "Use `solana-bn254` crate instead")] -pub mod alt_bn128 { - pub use solana_bn254::*; -} -#[cfg(feature = "full")] -#[deprecated(since = "2.3.0", note = "Use `solana-client-traits` crate instead")] -pub mod client { - pub use solana_client_traits::*; -} -#[deprecated( - since = "2.3.0", - note = "Use `solana-compute-budget-interface` crate instead" -)] -#[cfg(feature = "full")] -pub mod compute_budget { - pub use solana_compute_budget_interface::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana-decode-error` crate instead")] -pub mod decode_error { - pub use solana_decode_error::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana-derivation-path` crate instead")] -pub mod derivation_path { - pub use solana_derivation_path::*; -} -#[cfg(feature = "full")] -#[deprecated(since = "2.3.0", note = "Use `solana-ed25519-program` crate instead")] -pub mod ed25519_instruction { - pub use solana_ed25519_program::*; -} #[deprecated(since = "2.2.0", note = "Use `solana-epoch-info` crate instead")] pub use solana_epoch_info as epoch_info; #[deprecated( @@ -237,11 +80,6 @@ pub use solana_epoch_info as epoch_info; note = "Use `solana-epoch-rewards-hasher` crate instead" )] pub use solana_epoch_rewards_hasher as epoch_rewards_hasher; -#[deprecated(since = "2.2.2", note = "Use `agave-feature-set` crate instead")] -pub mod feature_set { - #[allow(deprecated)] - pub use solana_feature_set::*; -} #[deprecated(since = "2.2.0", note = "Use `solana-fee-structure` crate instead")] pub use solana_fee_structure as fee; #[deprecated(since = "2.1.0", note = "Use `solana-inflation` crate instead")] @@ -251,21 +89,9 @@ pub use solana_inflation as inflation; note = "Use `solana_message::inner_instruction` instead" )] pub use solana_message::inner_instruction; -#[deprecated(since = "2.3.0", note = "Use `solana-nonce-account` crate instead")] -pub mod nonce_account { - pub use solana_nonce_account::*; -} #[cfg(feature = "full")] #[deprecated(since = "2.2.0", note = "Use `solana-offchain-message` crate instead")] pub use solana_offchain_message as offchain_message; -#[deprecated(since = "2.3.0", note = "Use `solana-packet` crate instead")] -pub mod packet { - pub use solana_packet::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana-poh-config` crate instead")] -pub mod poh_config { - pub use solana_poh_config::*; -} #[deprecated(since = "2.1.0", note = "Use `solana-program-memory` crate instead")] pub use solana_program_memory as program_memory; #[deprecated(since = "2.1.0", note = "Use `solana_pubkey::pubkey` instead")] @@ -285,24 +111,6 @@ pub use solana_program_memory as program_memory; /// assert_eq!(ID, my_id); /// ``` pub use solana_pubkey::pubkey; -#[cfg(feature = "full")] -#[deprecated(since = "2.3.0", note = "Use `solana-quic-definitions` crate instead")] -pub mod quic { - pub use solana_quic_definitions::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana-rent-debits` crate instead")] -pub mod rent_debits { - pub use solana_rent_debits::*; -} -#[cfg(feature = "full")] -#[deprecated( - since = "2.2.2", - note = "Use `agave-reserved-account-keys` crate instead" -)] -pub mod reserved_account_keys { - #[allow(deprecated)] - pub use solana_reserved_account_keys::*; -} #[deprecated(since = "2.1.0", note = "Use `solana-sanitize` crate instead")] pub use solana_sanitize as sanitize; /// Same as `declare_id` except report that this id has been deprecated. @@ -331,29 +139,12 @@ pub use solana_sdk_macro::declare_deprecated_id; pub use solana_sdk_macro::declare_id; /// Convenience macro to define multiple static public keys. pub use solana_sdk_macro::pubkeys; -#[deprecated(since = "2.3.0", note = "Use `solana-secp256k1-program` crate instead")] -#[cfg(feature = "full")] -pub mod secp256k1_instruction { - pub use solana_secp256k1_program::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana-secp256k1-recover` crate instead")] -pub mod secp256k1_recover { - pub use solana_secp256k1_recover::*; -} #[deprecated(since = "2.2.0", note = "Use `solana-serde` crate instead")] pub use solana_serde as deserialize_utils; #[deprecated(since = "2.1.0", note = "Use `solana-serde-varint` crate instead")] pub use solana_serde_varint as serde_varint; #[deprecated(since = "2.1.0", note = "Use `solana-short-vec` crate instead")] pub use solana_short_vec as short_vec; -#[cfg(feature = "full")] -#[deprecated( - since = "2.3.0", - note = "Use `solana-system-transaction` crate instead" -)] -pub mod system_transaction { - pub use solana_system_transaction::*; -} #[deprecated(since = "2.2.0", note = "Use `solana-time-utils` crate instead")] pub use solana_time_utils as timing; #[cfg(feature = "full")] @@ -362,41 +153,5 @@ pub use solana_time_utils as timing; note = "Use `solana_transaction::simple_vote_transaction_checker` instead" )] pub use solana_transaction::simple_vote_transaction_checker; -#[deprecated( - since = "2.2.0", - note = "Use `solana-transaction-context` crate instead" -)] -pub mod transaction_context { - pub use solana_transaction_context::*; -} -#[deprecated(since = "2.3.0", note = "Use `solana-validator-exit` crate instead")] -pub mod exit { - pub use solana_validator_exit::*; -} - -/// Convenience macro for `AddAssign` with saturating arithmetic. -#[deprecated(since = "2.3.0", note = "Use `std::num::Saturating` instead")] -#[macro_export] -macro_rules! saturating_add_assign { - ($i:expr, $v:expr) => {{ - $i = $i.saturating_add($v) - }}; -} pub extern crate bs58; - -#[cfg(test)] -#[allow(deprecated)] -mod tests { - #[test] - fn test_saturating_add_assign() { - let mut i = 0u64; - let v = 1; - saturating_add_assign!(i, v); - assert_eq!(i, 1); - - i = u64::MAX; - saturating_add_assign!(i, v); - assert_eq!(i, u64::MAX); - } -} diff --git a/sdk/src/log.rs b/sdk/src/log.rs index 748b241c0..988ae703a 100644 --- a/sdk/src/log.rs +++ b/sdk/src/log.rs @@ -1,3 +1 @@ -#![cfg(feature = "program")] - pub use solana_program::log::*; diff --git a/sdk/src/native_loader.rs b/sdk/src/native_loader.rs index 976a758b2..3fae64ad2 100644 --- a/sdk/src/native_loader.rs +++ b/sdk/src/native_loader.rs @@ -1,5 +1,4 @@ //! The native loader native program. - use solana_account::{ Account, AccountSharedData, InheritableAccountFields, DUMMY_INHERITABLE_ACCOUNT_FIELDS, }; diff --git a/sdk/src/net.rs b/sdk/src/net.rs deleted file mode 100644 index bcc8520be..000000000 --- a/sdk/src/net.rs +++ /dev/null @@ -1,4 +0,0 @@ -use std::time::Duration; - -#[deprecated(since = "2.2.3", note = "This symbol is now private interface.")] -pub const DEFAULT_TPU_COALESCE: Duration = Duration::from_millis(5); diff --git a/sdk/src/precompiles.rs b/sdk/src/precompiles.rs deleted file mode 100644 index 303147f62..000000000 --- a/sdk/src/precompiles.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Solana precompiled programs. - -#![cfg(feature = "full")] - -#[deprecated(since = "2.1.0", note = "Use `solana-precompile-error` crate instead.")] -pub use solana_precompile_error::PrecompileError; -#[allow(deprecated)] -pub use solana_precompiles::{ - get_precompile, get_precompiles, is_precompile, verify_if_precompile, Precompile, Verify, -}; diff --git a/sdk/src/program_utils.rs b/sdk/src/program_utils.rs deleted file mode 100644 index 26bf7ebec..000000000 --- a/sdk/src/program_utils.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Contains a single utility function for deserializing from [bincode]. -//! -//! [bincode]: https://docs.rs/bincode - -use crate::instruction::InstructionError; - -/// Deserialize with a limit based the maximum amount of data a program can expect to get. -/// This function should be used in place of direct deserialization to help prevent OOM errors -#[deprecated( - since = "2.3.0", - note = "Use `solana_bincode::limited_deserialize` instead" -)] -pub fn limited_deserialize(instruction_data: &[u8]) -> Result -where - T: serde::de::DeserializeOwned, -{ - solana_program::program_utils::limited_deserialize( - instruction_data, - crate::packet::PACKET_DATA_SIZE as u64, - ) -} - -#[cfg(test)] -#[allow(deprecated)] -pub mod tests { - use super::*; - - #[test] - fn test_limited_deserialize() { - #[derive(serde_derive::Deserialize, serde_derive::Serialize)] - enum Foo { - Bar(Vec), - } - - let item = Foo::Bar([1; crate::packet::PACKET_DATA_SIZE - 12].to_vec()); // crate::packet::PACKET_DATA_SIZE - 12: size limit, minus enum variant and vec len() serialized sizes - let serialized = bincode::serialize(&item).unwrap(); - assert!(limited_deserialize::(&serialized).is_ok()); - - let item = Foo::Bar([1; crate::packet::PACKET_DATA_SIZE - 11].to_vec()); // Extra byte should bump serialized size over the size limit - let serialized = bincode::serialize(&item).unwrap(); - assert!(limited_deserialize::(&serialized).is_err()); - } -} diff --git a/sdk/src/pubkey.rs b/sdk/src/pubkey.rs index 344f06984..21bfa87b0 100644 --- a/sdk/src/pubkey.rs +++ b/sdk/src/pubkey.rs @@ -6,30 +6,3 @@ pub use solana_pubkey::{ bytes_are_curve_point, ParsePubkeyError, Pubkey, PubkeyError, MAX_SEEDS, MAX_SEED_LEN, PUBKEY_BYTES, }; - -#[deprecated(since = "2.1.0")] -#[cfg(feature = "full")] -pub fn write_pubkey_file(outfile: &str, pubkey: Pubkey) -> Result<(), Box> { - use std::io::Write; - - let printable = format!("{pubkey}"); - let serialized = serde_json::to_string(&printable)?; - - if let Some(outdir) = std::path::Path::new(&outfile).parent() { - std::fs::create_dir_all(outdir)?; - } - let mut f = std::fs::File::create(outfile)?; - f.write_all(&serialized.into_bytes())?; - - Ok(()) -} - -#[deprecated(since = "2.1.0")] -#[cfg(feature = "full")] -pub fn read_pubkey_file(infile: &str) -> Result> { - let f = std::fs::File::open(infile)?; - let printable: String = serde_json::from_reader(f)?; - - use std::str::FromStr; - Ok(Pubkey::from_str(&printable)?) -} diff --git a/sdk/src/rpc_port.rs b/sdk/src/rpc_port.rs deleted file mode 100644 index d7ca1fb7b..000000000 --- a/sdk/src/rpc_port.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![deprecated(since = "2.3.0", note = "Use `solana_rpc_client_api::port` instead")] -//! RPC default port numbers. - -/// Default port number for JSON RPC API -pub const DEFAULT_RPC_PORT: u16 = 8899; -pub const DEFAULT_RPC_PORT_STR: &str = "8899"; - -/// Default port number for JSON RPC pubsub -pub const DEFAULT_RPC_PUBSUB_PORT: u16 = 8900; diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs index 7e4864a3d..69cb46b7a 100644 --- a/sdk/src/transaction.rs +++ b/sdk/src/transaction.rs @@ -1,21 +1,15 @@ #![cfg(feature = "full")] +#[deprecated(since = "2.2.0", note = "Use solana_transaction crate instead")] +pub use solana_transaction::{ + sanitized::{MessageHash, SanitizedTransaction, TransactionAccountLocks, MAX_TX_ACCOUNT_LOCKS}, + uses_durable_nonce, + versioned::{ + sanitized::SanitizedVersionedTransaction, Legacy, TransactionVersion, VersionedTransaction, + }, + Transaction, TransactionVerificationMode, +}; #[deprecated(since = "2.2.0", note = "Use solana_transaction_error crate instead")] pub use solana_transaction_error::{ AddressLoaderError, SanitizeMessageError, TransactionError, TransactionResult as Result, TransportError, TransportResult, }; -#[deprecated(since = "2.2.0", note = "Use solana_transaction crate instead")] -pub use { - solana_program::message::{AddressLoader, SimpleAddressLoader}, - solana_transaction::{ - sanitized::{ - MessageHash, SanitizedTransaction, TransactionAccountLocks, MAX_TX_ACCOUNT_LOCKS, - }, - uses_durable_nonce, - versioned::{ - sanitized::SanitizedVersionedTransaction, Legacy, TransactionVersion, - VersionedTransaction, - }, - Transaction, TransactionVerificationMode, - }, -}; diff --git a/sdk/src/wasm/keypair.rs b/sdk/src/wasm/keypair.rs deleted file mode 100644 index 5c5da471a..000000000 --- a/sdk/src/wasm/keypair.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! This module is empty but has not yet been removed because that would -//! technically be a breaking change. There was never anything to import -//! from here. diff --git a/sdk/src/wasm/mod.rs b/sdk/src/wasm/mod.rs deleted file mode 100644 index 6946e730f..000000000 --- a/sdk/src/wasm/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! solana-sdk Javascript interface -#![cfg(target_arch = "wasm32")] - -pub mod keypair; -pub mod transaction; diff --git a/sdk/src/wasm/transaction.rs b/sdk/src/wasm/transaction.rs deleted file mode 100644 index 5c5da471a..000000000 --- a/sdk/src/wasm/transaction.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! This module is empty but has not yet been removed because that would -//! technically be a breaking change. There was never anything to import -//! from here. diff --git a/secp256k1-program/Cargo.toml b/secp256k1-program/Cargo.toml index 54cf71d88..c4f9bd817 100644 --- a/secp256k1-program/Cargo.toml +++ b/secp256k1-program/Cargo.toml @@ -17,9 +17,7 @@ rustdoc-args = ["--cfg=docsrs"] [features] bincode = [ "dep:bincode", - "dep:solana-feature-set", "dep:solana-instruction", - "dep:solana-precompile-error", "dep:solana-sdk-ids", "serde", ] @@ -29,28 +27,23 @@ serde = ["dep:serde", "dep:serde_derive"] [dependencies] bincode = { workspace = true, optional = true } digest = { workspace = true } -libsecp256k1 = { workspace = true, features = ["hmac"] } +k256 = { workspace = true, features = ["ecdsa-core"] } serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } sha3 = { workspace = true } -solana-feature-set = { workspace = true, optional = true } solana-instruction = { workspace = true, features = ["std"], optional = true } -solana-precompile-error = { workspace = true, optional = true } solana-sdk-ids = { workspace = true, optional = true } solana-signature = { workspace = true, features = ["std"] } [dev-dependencies] anyhow = { workspace = true } hex = { workspace = true } -rand0-7 = { workspace = true } +rand = { workspace = true } solana-account-info = { workspace = true } -solana-hash = { workspace = true } +solana-example-mocks = { path = "../example-mocks" } +solana-instruction = { workspace = true } solana-instructions-sysvar = { workspace = true } -solana-keccak-hasher = { workspace = true } -solana-keypair = { workspace = true } -solana-logger = { workspace = true } +solana-keccak-hasher = { workspace = true, features = ["sha3"] } solana-msg = { workspace = true } solana-program-error = { workspace = true } -solana-sdk = { path = "../sdk" } -solana-secp256k1-program = { path = ".", features = ["dev-context-only-utils"] } -solana-signer = { workspace = true } +solana-secp256k1-program = { path = ".", features = ["bincode"] } diff --git a/secp256k1-program/src/lib.rs b/secp256k1-program/src/lib.rs index c412993df..131196737 100644 --- a/secp256k1-program/src/lib.rs +++ b/secp256k1-program/src/lib.rs @@ -67,7 +67,7 @@ //! //! - In the client: //! - Sign the [`keccak`]-hashed messages with a secp256k1 ECDSA library, -//! like the [`libsecp256k1`] crate. +//! like the [`k256`] crate. //! - Build any custom instruction data that contains signature, message, or //! Ethereum address data that will be used by the secp256k1 instruction. //! - Build the secp256k1 program instruction data, specifying the number of @@ -102,9 +102,10 @@ //! the secp256k1 instruction data. It must be done manually. //! //! The secp256k1 program is implemented with the [`libsecp256k1`] crate, -//! which clients may also want to use. +//! but clients may want to use the [`k256`] crate. //! //! [`libsecp256k1`]: https://docs.rs/libsecp256k1/latest/libsecp256k1 +//! [`k256`]: https://docs.rs/k256/latest/k256 //! //! # Layout and interpretation of the secp256k1 instruction data //! @@ -269,8 +270,8 @@ //! and the Solana program will introspect the secp256k1 instruction to verify //! that the signer matches a known authorized public key. //! -//! The Solana program. Note that it uses `libsecp256k1` version 0.7.0 to parse -//! the secp256k1 signature to prevent malleability. +//! The Solana program. Note that it uses `k256` version 0.13.0 to parse the +//! secp256k1 signature to prevent malleability. //! //! ```no_run //! # mod secp256k1_defs { @@ -322,6 +323,7 @@ //! # })) //! # } //! # } +//! use k256::elliptic_curve::scalar::IsHigh; //! use solana_account_info::{next_account_info, AccountInfo}; //! use solana_msg::msg; //! use solana_program_error::{ProgramError, ProgramResult}; @@ -388,10 +390,10 @@ //! { //! let signature = &secp256k1_instr.data[offsets.signature_offset as usize //! ..offsets.signature_offset as usize + secp256k1_defs::SIGNATURE_SERIALIZED_SIZE]; -//! let signature = libsecp256k1::Signature::parse_standard_slice(signature) +//! let signature = k256::ecdsa::Signature::from_slice(signature) //! .map_err(|_| ProgramError::InvalidArgument)?; //! -//! if signature.s.is_high() { +//! if bool::from(signature.s().is_high()) { //! msg!("signature with high-s value"); //! return Err(ProgramError::InvalidArgument); //! } @@ -418,13 +420,13 @@ //! The client program: //! //! ```no_run -//! # use solana_sdk::example_mocks::solana_rpc_client; +//! # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; //! use anyhow::Result; //! use solana_instruction::{AccountMeta, Instruction}; //! use solana_keypair::Keypair; //! use solana_rpc_client::rpc_client::RpcClient; //! use solana_signer::Signer; -//! use solana_sdk::transaction::Transaction; +//! use solana_transaction::Transaction; //! use solana_secp256k1_program::{ //! eth_address_from_pubkey, new_secp256k1_instruction_with_signature, //! sign_message, @@ -432,16 +434,16 @@ //! //! fn demo_secp256k1_verify_basic( //! payer_keypair: &Keypair, -//! secp256k1_secret_key: &libsecp256k1::SecretKey, +//! secp256k1_secret_key: &k256::ecdsa::SigningKey, //! client: &RpcClient, //! program_keypair: &Keypair, //! ) -> Result<()> { //! // Internally to `sign_message` and `secp256k_instruction::verify` //! // (the secp256k1 program), this message is keccak-hashed before signing. //! let msg = b"hello world"; -//! let secp_pubkey = libsecp256k1::PublicKey::from_secret_key(secp256k1_secret_key); -//! let eth_address = eth_address_from_pubkey(&secp_pubkey.serialize()[1..].try_into().unwrap()); -//! let (signature, recovery_id) = sign_message(&secp256k1_secret_key.serialize(), msg).unwrap(); +//! let secp_pubkey = secp256k1_secret_key.verifying_key(); +//! let eth_address = eth_address_from_pubkey(&secp_pubkey.to_encoded_point(false).as_bytes()[1..].try_into().unwrap()); +//! let (signature, recovery_id) = sign_message(&secp256k1_secret_key.to_bytes().into(), msg).unwrap(); //! let secp256k1_instr = new_secp256k1_instruction_with_signature(msg, &signature, recovery_id, ð_address); //! //! let program_instr = Instruction::new_with_bytes( @@ -634,7 +636,7 @@ //! The client program: //! //! ```no_run -//! # use solana_sdk::example_mocks::solana_rpc_client; +//! # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; //! use anyhow::Result; //! use solana_instruction::{AccountMeta, Instruction}; //! use solana_rpc_client::rpc_client::RpcClient; @@ -644,7 +646,7 @@ //! }; //! use solana_signer::Signer; //! use solana_keypair::Keypair; -//! use solana_sdk::transaction::Transaction; +//! use solana_transaction::Transaction; //! //! /// A struct to hold the values specified in the `SecpSignatureOffsets` struct. //! struct SecpSignature { @@ -731,21 +733,21 @@ //! // Sign some messages. //! let mut signatures = vec![]; //! for idx in 0..2 { -//! let secret_key = libsecp256k1::SecretKey::random(&mut rand0_7::thread_rng()); +//! let secret_key = k256::ecdsa::SigningKey::random(&mut rand::thread_rng()); //! let message = format!("hello world {}", idx).into_bytes(); //! let message_hash = { //! let mut hasher = solana_keccak_hasher::Hasher::default(); //! hasher.hash(&message); //! hasher.result() //! }; -//! let secp_message = libsecp256k1::Message::parse(&message_hash.0); -//! let (signature, recovery_id) = libsecp256k1::sign(&secp_message, &secret_key); -//! let signature = signature.serialize(); -//! let recovery_id = recovery_id.serialize(); +//! let (signature, recovery_id) = +//! secret_key.sign_prehash_recoverable(message_hash.as_bytes()).unwrap(); +//! let signature = signature.to_bytes().into(); +//! let recovery_id = recovery_id.to_byte(); //! -//! let public_key = libsecp256k1::PublicKey::from_secret_key(&secret_key); +//! let public_key = secret_key.verifying_key(); //! let eth_address = -//! eth_address_from_pubkey(&public_key.serialize()[1..].try_into().unwrap()); +//! eth_address_from_pubkey(&public_key.to_encoded_point(false).as_bytes()[1..].try_into().unwrap()); //! //! signatures.push(SecpSignature { //! signature, @@ -786,9 +788,9 @@ #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; -use {digest::Digest, solana_signature::error::Error}; #[cfg(feature = "bincode")] -use {solana_instruction::Instruction, solana_precompile_error::PrecompileError}; +use solana_instruction::Instruction; +use {digest::Digest, solana_signature::error::Error}; pub const SECP256K1_PUBKEY_SIZE: usize = 64; pub const SECP256K1_PRIVATE_KEY_SIZE: usize = 32; @@ -822,54 +824,22 @@ pub struct SecpSignatureOffsets { pub message_instruction_index: u8, } -/// Sign a message and create a secp256k1 program instruction to verify the signature. -/// -/// This function is suitable for simple uses of the secp256k1 program. -/// More complex uses must encode the secp256k1 instruction data manually. -/// See the [module documentation][md] for examples. -/// -/// [md]: self -/// -/// The instruction generated by this function must be the first instruction -/// included in a transaction or it will not verify. The -/// [`SecpSignatureOffsets`] structure encoded in the instruction data specify -/// the instruction indexes as 0. -/// -/// `message_arr` is hashed with the [`keccak`] hash function prior to signing. -/// -/// [`keccak`]: https://docs.rs/solana-sdk/latest/solana_sdk/keccak/index.html -#[cfg(feature = "bincode")] -#[deprecated( - since = "2.2.2", - note = "Use `new_secp256k1_instruction_with_signature` instead" -)] -pub fn new_secp256k1_instruction( - priv_key: &libsecp256k1::SecretKey, - message_arr: &[u8], -) -> Instruction { - let secp_pubkey = libsecp256k1::PublicKey::from_secret_key(priv_key); - let eth_address = eth_address_from_pubkey(&secp_pubkey.serialize()[1..].try_into().unwrap()); - // unwrap is safe because priv_key is already valid - let (signature, recovery_id) = sign_message(&priv_key.serialize(), message_arr).unwrap(); - new_secp256k1_instruction_with_signature(message_arr, &signature, recovery_id, ð_address) -} - /// Signs a message from the given private key bytes pub fn sign_message( priv_key_bytes: &[u8; SECP256K1_PRIVATE_KEY_SIZE], message: &[u8], ) -> Result<([u8; SIGNATURE_SERIALIZED_SIZE], u8), Error> { - let priv_key = libsecp256k1::SecretKey::parse(priv_key_bytes) + let priv_key = k256::ecdsa::SigningKey::from_slice(priv_key_bytes) .map_err(|e| Error::from_source(format!("{e}")))?; let mut hasher = sha3::Keccak256::new(); hasher.update(message); let message_hash = hasher.finalize(); let mut message_hash_arr = [0u8; 32]; message_hash_arr.copy_from_slice(message_hash.as_slice()); - let message = libsecp256k1::Message::parse(&message_hash_arr); - let (signature, recovery_id) = libsecp256k1::sign(&message, &priv_key); - let signature_arr = signature.serialize(); - Ok((signature_arr, recovery_id.serialize())) + let (signature, recovery_id) = priv_key + .sign_prehash_recoverable(&message_hash_arr) + .map_err(|e| Error::from_source(format!("{e}")))?; + Ok((signature.to_bytes().into(), recovery_id.to_byte())) } #[cfg(feature = "bincode")] @@ -922,17 +892,6 @@ pub fn new_secp256k1_instruction_with_signature( } } -/// Creates an Ethereum address from a secp256k1 public key. -#[deprecated(since = "2.2.2", note = "Use `eth_address_from_pubkey` instead")] -pub fn construct_eth_pubkey( - pubkey: &libsecp256k1::PublicKey, -) -> [u8; HASHED_PUBKEY_SERIALIZED_SIZE] { - let mut addr = [0u8; HASHED_PUBKEY_SERIALIZED_SIZE]; - addr.copy_from_slice(&sha3::Keccak256::digest(&pubkey.serialize()[1..])[12..]); - assert_eq!(addr.len(), HASHED_PUBKEY_SERIALIZED_SIZE); - addr -} - /// Creates an Ethereum address from a secp256k1 public key. pub fn eth_address_from_pubkey( pubkey: &[u8; SECP256K1_PUBKEY_SIZE], @@ -942,418 +901,3 @@ pub fn eth_address_from_pubkey( assert_eq!(addr.len(), HASHED_PUBKEY_SERIALIZED_SIZE); addr } - -/// Verifies the signatures specified in the secp256k1 instruction data. -/// -/// This is the same as the verification routine executed by the runtime's secp256k1 native program, -/// and is primarily of use to the runtime. -/// -/// `data` is the secp256k1 program's instruction data. `instruction_datas` is -/// the full slice of instruction datas for all instructions in the transaction, -/// including the secp256k1 program's instruction data. -/// -/// `feature_set` is the set of active Solana features. It is used to enable or -/// disable a few minor additional checks that were activated on chain -/// subsequent to the addition of the secp256k1 native program. For many -/// purposes passing `FeatureSet::all_enabled()` is reasonable. -#[cfg(feature = "bincode")] -#[deprecated( - since = "2.2.2", - note = "Use agave_precompiles::secp256k1::verify instead" -)] -#[allow(deprecated)] -pub fn verify( - data: &[u8], - instruction_datas: &[&[u8]], - _feature_set: &solana_feature_set::FeatureSet, -) -> Result<(), PrecompileError> { - if data.is_empty() { - return Err(PrecompileError::InvalidInstructionDataSize); - } - let count = data[0] as usize; - if count == 0 && data.len() > 1 { - // count is zero but the instruction data indicates that is probably not - // correct, fail the instruction to catch probable invalid secp256k1 - // instruction construction. - return Err(PrecompileError::InvalidInstructionDataSize); - } - let expected_data_size = count - .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) - .saturating_add(1); - if data.len() < expected_data_size { - return Err(PrecompileError::InvalidInstructionDataSize); - } - for i in 0..count { - let start = i - .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) - .saturating_add(1); - let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE); - - let offsets: SecpSignatureOffsets = bincode::deserialize(&data[start..end]) - .map_err(|_| PrecompileError::InvalidSignature)?; - - // Parse out signature - let signature_index = offsets.signature_instruction_index as usize; - if signature_index >= instruction_datas.len() { - return Err(PrecompileError::InvalidInstructionDataSize); - } - let signature_instruction = instruction_datas[signature_index]; - let sig_start = offsets.signature_offset as usize; - let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE); - if sig_end >= signature_instruction.len() { - return Err(PrecompileError::InvalidSignature); - } - - let signature = libsecp256k1::Signature::parse_standard_slice( - &signature_instruction[sig_start..sig_end], - ) - .map_err(|_| PrecompileError::InvalidSignature)?; - - let recovery_id = libsecp256k1::RecoveryId::parse(signature_instruction[sig_end]) - .map_err(|_| PrecompileError::InvalidRecoveryId)?; - - // Parse out pubkey - let eth_address_slice = get_data_slice( - instruction_datas, - offsets.eth_address_instruction_index, - offsets.eth_address_offset, - HASHED_PUBKEY_SERIALIZED_SIZE, - )?; - - // Parse out message - let message_slice = get_data_slice( - instruction_datas, - offsets.message_instruction_index, - offsets.message_data_offset, - offsets.message_data_size as usize, - )?; - - let mut hasher = sha3::Keccak256::new(); - hasher.update(message_slice); - let message_hash = hasher.finalize(); - - let pubkey = libsecp256k1::recover( - &libsecp256k1::Message::parse_slice(&message_hash).unwrap(), - &signature, - &recovery_id, - ) - .map_err(|_| PrecompileError::InvalidSignature)?; - let eth_address = eth_address_from_pubkey(&pubkey.serialize()[1..].try_into().unwrap()); - - if eth_address_slice != eth_address { - return Err(PrecompileError::InvalidSignature); - } - } - Ok(()) -} - -#[cfg(feature = "bincode")] -fn get_data_slice<'a>( - instruction_datas: &'a [&[u8]], - instruction_index: u8, - offset_start: u16, - size: usize, -) -> Result<&'a [u8], PrecompileError> { - let signature_index = instruction_index as usize; - if signature_index >= instruction_datas.len() { - return Err(PrecompileError::InvalidDataOffsets); - } - let signature_instruction = &instruction_datas[signature_index]; - let start = offset_start as usize; - let end = start.saturating_add(size); - if end > signature_instruction.len() { - return Err(PrecompileError::InvalidSignature); - } - - Ok(&instruction_datas[signature_index][start..end]) -} - -#[cfg(test)] -#[allow(deprecated)] -pub mod test { - use { - super::*, - rand0_7::{thread_rng, Rng}, - solana_feature_set::FeatureSet, - solana_hash::Hash, - solana_keccak_hasher as keccak, - solana_keypair::Keypair, - solana_sdk::transaction::Transaction, - solana_signer::Signer, - }; - - fn test_case( - num_signatures: u8, - offsets: &SecpSignatureOffsets, - ) -> Result<(), PrecompileError> { - let mut instruction_data = vec![0u8; DATA_START]; - instruction_data[0] = num_signatures; - let writer = std::io::Cursor::new(&mut instruction_data[1..]); - bincode::serialize_into(writer, &offsets).unwrap(); - let feature_set = FeatureSet::all_enabled(); - verify(&instruction_data, &[&[0u8; 100]], &feature_set) - } - - #[test] - fn test_invalid_offsets() { - solana_logger::setup(); - - let mut instruction_data = vec![0u8; DATA_START]; - let offsets = SecpSignatureOffsets::default(); - instruction_data[0] = 1; - let writer = std::io::Cursor::new(&mut instruction_data[1..]); - bincode::serialize_into(writer, &offsets).unwrap(); - instruction_data.truncate(instruction_data.len() - 1); - let feature_set = FeatureSet::all_enabled(); - - assert_eq!( - verify(&instruction_data, &[&[0u8; 100]], &feature_set), - Err(PrecompileError::InvalidInstructionDataSize) - ); - - let offsets = SecpSignatureOffsets { - signature_instruction_index: 1, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidInstructionDataSize) - ); - - let offsets = SecpSignatureOffsets { - message_instruction_index: 1, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = SecpSignatureOffsets { - eth_address_instruction_index: 1, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_message_data_offsets() { - let offsets = SecpSignatureOffsets { - message_data_offset: 99, - message_data_size: 1, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - - let offsets = SecpSignatureOffsets { - message_data_offset: 100, - message_data_size: 1, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - - let offsets = SecpSignatureOffsets { - message_data_offset: 100, - message_data_size: 1000, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - - let offsets = SecpSignatureOffsets { - message_data_offset: u16::MAX, - message_data_size: u16::MAX, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - } - - #[test] - fn test_eth_offset() { - let offsets = SecpSignatureOffsets { - eth_address_offset: u16::MAX, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - - let offsets = SecpSignatureOffsets { - eth_address_offset: 100 - HASHED_PUBKEY_SERIALIZED_SIZE as u16 + 1, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - } - - #[test] - fn test_signature_offset() { - let offsets = SecpSignatureOffsets { - signature_offset: u16::MAX, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - - let offsets = SecpSignatureOffsets { - signature_offset: 100 - SIGNATURE_SERIALIZED_SIZE as u16 + 1, - ..SecpSignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - } - - #[test] - fn test_count_is_zero_but_sig_data_exists() { - solana_logger::setup(); - - let mut instruction_data = vec![0u8; DATA_START]; - let offsets = SecpSignatureOffsets::default(); - instruction_data[0] = 0; - let writer = std::io::Cursor::new(&mut instruction_data[1..]); - bincode::serialize_into(writer, &offsets).unwrap(); - let feature_set = FeatureSet::all_enabled(); - - assert_eq!( - verify(&instruction_data, &[&[0u8; 100]], &feature_set), - Err(PrecompileError::InvalidInstructionDataSize) - ); - } - - #[test] - fn test_secp256k1() { - solana_logger::setup(); - let offsets = SecpSignatureOffsets::default(); - assert_eq!( - bincode::serialized_size(&offsets).unwrap() as usize, - SIGNATURE_OFFSETS_SERIALIZED_SIZE - ); - - let secp_privkey = libsecp256k1::SecretKey::random(&mut thread_rng()); - let message_arr = b"hello"; - let secp_pubkey = libsecp256k1::PublicKey::from_secret_key(&secp_privkey); - let eth_address = - eth_address_from_pubkey(&secp_pubkey.serialize()[1..].try_into().unwrap()); - // unwrap is safe because priv_key is already valid - let (signature, recovery_id) = - sign_message(&secp_privkey.serialize(), message_arr).unwrap(); - let mut secp_instruction = new_secp256k1_instruction_with_signature( - message_arr, - &signature, - recovery_id, - ð_address, - ); - let mint_keypair = Keypair::new(); - let feature_set = solana_feature_set::FeatureSet::all_enabled(); - - let tx = Transaction::new_signed_with_payer( - &[secp_instruction.clone()], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - - assert!(tx.verify_precompiles(&feature_set).is_ok()); - - let index = thread_rng().gen_range(0, secp_instruction.data.len()); - secp_instruction.data[index] = secp_instruction.data[index].wrapping_add(12); - let tx = Transaction::new_signed_with_payer( - &[secp_instruction], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - assert!(tx.verify_precompiles(&feature_set).is_err()); - } - - // Signatures are malleable. - #[test] - fn test_malleability() { - solana_logger::setup(); - - let secret_key = libsecp256k1::SecretKey::random(&mut thread_rng()); - let public_key = libsecp256k1::PublicKey::from_secret_key(&secret_key); - let eth_address = eth_address_from_pubkey(&public_key.serialize()[1..].try_into().unwrap()); - - let message = b"hello"; - let message_hash = { - let mut hasher = keccak::Hasher::default(); - hasher.hash(message); - hasher.result() - }; - - let secp_message = libsecp256k1::Message::parse(&message_hash.0); - let (signature, recovery_id) = libsecp256k1::sign(&secp_message, &secret_key); - - // Flip the S value in the signature to make a different but valid signature. - let mut alt_signature = signature; - alt_signature.s = -alt_signature.s; - let alt_recovery_id = libsecp256k1::RecoveryId::parse(recovery_id.serialize() ^ 1).unwrap(); - - let mut data: Vec = vec![]; - let mut both_offsets = vec![]; - - // Verify both signatures of the same message. - let sigs = [(signature, recovery_id), (alt_signature, alt_recovery_id)]; - for (signature, recovery_id) in sigs.iter() { - let signature_offset = data.len(); - data.extend(signature.serialize()); - data.push(recovery_id.serialize()); - let eth_address_offset = data.len(); - data.extend(eth_address); - let message_data_offset = data.len(); - data.extend(message); - - let data_start = 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE * 2; - - let offsets = SecpSignatureOffsets { - signature_offset: (signature_offset + data_start) as u16, - signature_instruction_index: 0, - eth_address_offset: (eth_address_offset + data_start) as u16, - eth_address_instruction_index: 0, - message_data_offset: (message_data_offset + data_start) as u16, - message_data_size: message.len() as u16, - message_instruction_index: 0, - }; - - both_offsets.push(offsets); - } - - let mut instruction_data: Vec = vec![2]; - - for offsets in both_offsets { - let offsets = bincode::serialize(&offsets).unwrap(); - instruction_data.extend(offsets); - } - - instruction_data.extend(data); - - verify( - &instruction_data, - &[&instruction_data], - &FeatureSet::all_enabled(), - ) - .unwrap(); - } -} diff --git a/secp256k1-recover/Cargo.toml b/secp256k1-recover/Cargo.toml index edaea7d60..1d4543aac 100644 --- a/secp256k1-recover/Cargo.toml +++ b/secp256k1-recover/Cargo.toml @@ -27,7 +27,7 @@ solana-frozen-abi-macro = { workspace = true, optional = true, features = [ thiserror = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] -libsecp256k1 = { workspace = true } +k256 = { workspace = true } [target.'cfg(target_os = "solana")'.dependencies] solana-define-syscall = { workspace = true } @@ -35,10 +35,11 @@ solana-define-syscall = { workspace = true } [dev-dependencies] anyhow = { workspace = true } borsh = { workspace = true } +rand = { workspace = true } solana-program = { path = "../program" } [target.'cfg(not(target_os = "solana"))'.dev-dependencies] -libsecp256k1 = { workspace = true, features = ["hmac"] } +k256 = { workspace = true, features = ["ecdsa-core"] } [lints] workspace = true diff --git a/secp256k1-recover/src/lib.rs b/secp256k1-recover/src/lib.rs index 1cc31d0d8..ac0ce42bc 100644 --- a/secp256k1-recover/src/lib.rs +++ b/secp256k1-recover/src/lib.rs @@ -130,9 +130,11 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// [sp]: https://docs.rs/solana-program/latest/solana_program/secp256k1_program/ /// /// The `secp256k1_recover` syscall is implemented with the [`libsecp256k1`] -/// crate, which clients may also want to use. +/// crate, but clients may want to use [`k256`] for an up-to-date pure Rust +/// implementation. /// /// [`libsecp256k1`]: https://docs.rs/libsecp256k1/latest/libsecp256k1 +/// [`k256`]: https://docs.rs/k256/latest/k256 /// /// # Hashing messages /// @@ -166,6 +168,7 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// this: /// /// ```rust +/// # use k256::elliptic_curve::scalar::IsHigh; /// # use solana_program::program_error::ProgramError; /// # let signature_bytes = [ /// # 0x83, 0x55, 0x81, 0xDF, 0xB1, 0x02, 0xA7, 0xD2, @@ -177,21 +180,15 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// # 0x1E, 0xBF, 0x06, 0x8E, 0x8A, 0x9F, 0xA9, 0xC3, /// # 0xA5, 0xEA, 0x21, 0xAC, 0xED, 0x5B, 0x22, 0x13, /// # ]; -/// let signature = libsecp256k1::Signature::parse_standard_slice(&signature_bytes) +/// let signature = k256::ecdsa::Signature::from_slice(&signature_bytes) /// .map_err(|_| ProgramError::InvalidArgument)?; /// -/// if signature.s.is_high() { +/// if bool::from(signature.s().is_high()) { /// return Err(ProgramError::InvalidArgument); /// } /// # Ok::<_, ProgramError>(()) /// ``` /// -/// This has the downside that the program must link to the [`libsecp256k1`] -/// crate and parse the signature just for this check. Note that `libsecp256k1` -/// version 0.7.0 or greater is required for running on the Solana SBF target. -/// -/// [`libsecp256k1`]: https://docs.rs/libsecp256k1/latest/libsecp256k1 -/// /// For the most accurate description of signature malleability, and its /// prevention in secp256k1, refer to comments in [`secp256k1.h`] in the Bitcoin /// Core secp256k1 library, the documentation of the [OpenZeppelin `recover` @@ -258,10 +255,11 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// } /// ``` /// -/// The Solana program. Note that it uses `libsecp256k1` version 0.7.0 to parse +/// The Solana program. Note that it uses `k256` version 0.13.0 to parse /// the secp256k1 signature to prevent malleability. /// -/// ```rust,no_run +/// ```rust +/// use k256::elliptic_curve::scalar::IsHigh; /// use solana_program::{ /// entrypoint::ProgramResult, /// keccak, msg, @@ -269,14 +267,6 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// }; /// use solana_secp256k1_recover::secp256k1_recover; /// -/// /// The key we expect to sign secp256k1 messages, -/// /// as serialized by `libsecp256k1::PublicKey::serialize`. -/// const AUTHORIZED_PUBLIC_KEY: [u8; 64] = [ -/// 0x8C, 0xD6, 0x47, 0xF8, 0xA5, 0xBF, 0x59, 0xA0, 0x4F, 0x77, 0xFA, 0xFA, 0x6C, 0xA0, 0xE6, 0x4D, -/// 0x94, 0x5B, 0x46, 0x55, 0xA6, 0x2B, 0xB0, 0x6F, 0x10, 0x4C, 0x9E, 0x2C, 0x6F, 0x42, 0x0A, 0xBE, -/// 0x18, 0xDF, 0x0B, 0xF0, 0x87, 0x42, 0xBA, 0x88, 0xB4, 0xCF, 0x87, 0x5A, 0x35, 0x27, 0xBE, 0x0F, -/// 0x45, 0xAE, 0xFC, 0x66, 0x9C, 0x2C, 0x6B, 0xF3, 0xEF, 0xCA, 0x5C, 0x32, 0x11, 0xF7, 0x2A, 0xC7, -/// ]; /// # pub struct DemoSecp256k1RecoverInstruction { /// # pub message: Vec, /// # pub signature: [u8; 64], @@ -285,6 +275,7 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// /// pub fn process_secp256k1_recover( /// instruction: DemoSecp256k1RecoverInstruction, +/// expected_public_key: [u8; 64], /// ) -> ProgramResult { /// // The secp256k1 recovery operation accepts a cryptographically-hashed /// // message only. Passing it anything else is insecure and allows signatures @@ -302,17 +293,17 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// // Solana does not do this itself. /// // This may or may not be necessary depending on use case. /// { -/// let signature = libsecp256k1::Signature::parse_standard_slice(&instruction.signature) +/// let signature = k256::ecdsa::Signature::from_slice(&instruction.signature) /// .map_err(|_| ProgramError::InvalidArgument)?; /// -/// if signature.s.is_high() { +/// if bool::from(signature.s().is_high()) { /// msg!("signature with high-s value"); /// return Err(ProgramError::InvalidArgument); /// } /// } /// /// let recovered_pubkey = secp256k1_recover( -/// &message_hash.0, +/// message_hash.as_bytes(), /// instruction.recovery_id, /// &instruction.signature, /// ) @@ -321,17 +312,34 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// // If we're using this function for signature verification then we /// // need to check the pubkey is an expected value. /// // Here we are checking the secp256k1 pubkey against a known authorized pubkey. -/// if recovered_pubkey.0 != AUTHORIZED_PUBLIC_KEY { +/// if recovered_pubkey.0 != expected_public_key { /// return Err(ProgramError::InvalidArgument); /// } /// /// Ok(()) /// } +/// +/// let secret_key = k256::ecdsa::SigningKey::random(&mut rand::thread_rng()); +/// let public_key = &secret_key.verifying_key().to_encoded_point(false); +/// let message = b"hello world!"; +/// let message_hash = { +/// let mut hasher = keccak::Hasher::default(); +/// hasher.hash(message); +/// hasher.result() +/// }; +/// let (signature, recovery_id) = secret_key.sign_prehash_recoverable(message_hash.as_bytes()).unwrap(); +/// let signature = signature.to_bytes().into(); +/// let instruction = DemoSecp256k1RecoverInstruction { +/// message: message.to_vec(), +/// signature, +/// recovery_id: recovery_id.to_byte(), +/// }; +/// process_secp256k1_recover(instruction, public_key.as_bytes()[1..65].try_into().unwrap()).unwrap(); /// ``` /// /// The RPC client program: /// -/// ```rust,no_run +/// ```rust /// # use solana_program::example_mocks::solana_rpc_client; /// # use solana_program::example_mocks::solana_sdk; /// use anyhow::Result; @@ -354,7 +362,7 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// /// pub fn demo_secp256k1_recover( /// payer_keypair: &Keypair, -/// secp256k1_secret_key: &libsecp256k1::SecretKey, +/// secp256k1_secret_key: &k256::ecdsa::SigningKey, /// client: &RpcClient, /// program_keypair: &Keypair, /// ) -> Result<()> { @@ -365,15 +373,14 @@ pub use solana_define_syscall::definitions::sol_secp256k1_recover; /// hasher.result() /// }; /// -/// let secp_message = libsecp256k1::Message::parse(&message_hash.0); -/// let (signature, recovery_id) = libsecp256k1::sign(&secp_message, &secp256k1_secret_key); +/// let (signature, recovery_id) = secp256k1_secret_key.sign_prehash_recoverable(message_hash.as_bytes()).unwrap(); /// -/// let signature = signature.serialize(); +/// let signature = signature.to_bytes().into(); /// /// let instr = DemoSecp256k1RecoverInstruction { /// message: message.to_vec(), /// signature, -/// recovery_id: recovery_id.serialize(), +/// recovery_id: recovery_id.to_byte(), /// }; /// let instr = Instruction::new_with_borsh( /// program_keypair.pubkey(), @@ -419,14 +426,19 @@ pub fn secp256k1_recover( #[cfg(not(target_os = "solana"))] { - let message = libsecp256k1::Message::parse_slice(hash) - .map_err(|_| Secp256k1RecoverError::InvalidHash)?; - let recovery_id = libsecp256k1::RecoveryId::parse(recovery_id) + const HASH_SIZE: usize = 32; + if hash.len() != HASH_SIZE { + return Err(Secp256k1RecoverError::InvalidHash); + } + let recovery_id = k256::ecdsa::RecoveryId::try_from(recovery_id) .map_err(|_| Secp256k1RecoverError::InvalidRecoveryId)?; - let signature = libsecp256k1::Signature::parse_standard_slice(signature) - .map_err(|_| Secp256k1RecoverError::InvalidSignature)?; - let secp256k1_key = libsecp256k1::recover(&message, &signature, &recovery_id) + let signature = k256::ecdsa::Signature::from_slice(signature) .map_err(|_| Secp256k1RecoverError::InvalidSignature)?; - Ok(Secp256k1Pubkey::new(&secp256k1_key.serialize()[1..65])) + let secp256k1_key = + k256::ecdsa::VerifyingKey::recover_from_prehash(hash, &signature, recovery_id) + .map_err(|_| Secp256k1RecoverError::InvalidSignature)?; + Ok(Secp256k1Pubkey::new( + &secp256k1_key.to_encoded_point(false).as_bytes()[1..65], + )) } } diff --git a/secp256r1-program/Cargo.toml b/secp256r1-program/Cargo.toml index e4318ffcb..ee2c774be 100644 --- a/secp256r1-program/Cargo.toml +++ b/secp256r1-program/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-secp256r1-program" description = "Precompile implementation for the secp256r1 elliptic curve." documentation = "https://docs.rs/solana-secp256r1" version = "2.2.4" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -20,17 +21,11 @@ openssl-vendored = ["openssl/vendored"] [dependencies] bytemuck = { workspace = true, features = ["derive"] } -solana-feature-set = { workspace = true } -solana-precompile-error = { workspace = true } solana-sdk-ids = { workspace = true } [target.'cfg(all(not(target_arch = "wasm32"), not(target_os = "solana")))'.dependencies] openssl = { workspace = true } solana-instruction = { workspace = true, features = ["std"] } -[dev-dependencies] -solana-logger = { workspace = true } -solana-sdk = { path = "../sdk" } - [lints] workspace = true diff --git a/secp256r1-program/src/lib.rs b/secp256r1-program/src/lib.rs index 9a3211ffd..221bb80ec 100644 --- a/secp256r1-program/src/lib.rs +++ b/secp256r1-program/src/lib.rs @@ -1,5 +1,5 @@ -//! Instructions for the [secp256r1 native program][np]. -//! [np]: https://docs.solana.com/developing/runtime-facilities/programs#secp256r1-program +//! Instructions for the +//! [secp256r1 native program](https://docs.solana.com/developing/runtime-facilities/programs#secp256r1-program) //! //! Note on Signature Malleability: //! This precompile requires low-S values in signatures (s <= half_curve_order) to prevent signature malleability. @@ -42,16 +42,8 @@ mod target_arch { use { crate::Secp256r1SignatureOffsets, bytemuck::bytes_of, - openssl::{ - bn::{BigNum, BigNumContext}, - ec::{EcGroup, EcKey, EcPoint}, - ecdsa::EcdsaSig, - nid::Nid, - pkey::{PKey, Private}, - sign::{Signer, Verifier}, - }, + openssl::{bn::BigNum, ec::EcKey, ecdsa::EcdsaSig, nid::Nid, pkey::PKey, sign::Signer}, solana_instruction::Instruction, - solana_precompile_error::PrecompileError, }; pub const COMPRESSED_PUBKEY_SERIALIZED_SIZE: usize = 33; @@ -83,36 +75,10 @@ mod target_arch { // Field size in bytes pub const FIELD_SIZE: usize = 32; - #[deprecated( - since = "2.2.3", - note = "Use `new_secp256r1_instruction_with_signature` and `sign_message` instead" - )] - pub fn new_secp256r1_instruction( - message: &[u8], - signing_key: EcKey, - ) -> Result> { - let signature = sign_message(message, &signing_key.private_key_to_der()?)?; - - let mut ctx = BigNumContext::new()?; - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?; - let pubkey = signing_key.public_key().to_bytes( - &group, - openssl::ec::PointConversionForm::COMPRESSED, - &mut ctx, - )?; - assert_eq!(pubkey.len(), COMPRESSED_PUBKEY_SERIALIZED_SIZE); - - Ok(new_secp256r1_instruction_with_signature( - message, - &signature, - &pubkey.try_into().unwrap(), // len was just checked, this is safe - )) - } - pub fn sign_message( message: &[u8], priv_key_bytes_der: &[u8], - ) -> Result<[u8; SIGNATURE_SERIALIZED_SIZE], Box> { + ) -> Result<[u8; SIGNATURE_SERIALIZED_SIZE], Box> { let signing_key = EcKey::private_key_from_der(priv_key_bytes_der)?; if signing_key.group().curve_name() != Some(Nid::X9_62_PRIME256V1) { return Err(("Signing key must be on the secp256r1 curve".to_string()).into()); @@ -197,654 +163,6 @@ mod target_arch { data: instruction_data, } } - - #[deprecated( - since = "2.2.3", - note = "Use agave_precompiles::secp256r1::verify instead" - )] - #[allow(deprecated)] - pub fn verify( - data: &[u8], - instruction_datas: &[&[u8]], - _feature_set: &solana_feature_set::FeatureSet, - ) -> Result<(), PrecompileError> { - if data.len() < SIGNATURE_OFFSETS_START { - return Err(PrecompileError::InvalidInstructionDataSize); - } - let num_signatures = data[0] as usize; - if num_signatures == 0 { - return Err(PrecompileError::InvalidInstructionDataSize); - } - if num_signatures > 8 { - return Err(PrecompileError::InvalidInstructionDataSize); - } - - let expected_data_size = num_signatures - .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) - .saturating_add(SIGNATURE_OFFSETS_START); - - // We do not check or use the byte at data[1] - if data.len() < expected_data_size { - return Err(PrecompileError::InvalidInstructionDataSize); - } - - // Parse half order from constant - let half_order: BigNum = BigNum::from_slice(&SECP256R1_HALF_ORDER) - .map_err(|_| PrecompileError::InvalidSignature)?; - - // Parse order - 1 from constant - let order_minus_one: BigNum = BigNum::from_slice(&SECP256R1_ORDER_MINUS_ONE) - .map_err(|_| PrecompileError::InvalidSignature)?; - - // Create a BigNum for 1 - let one = BigNum::from_u32(1).map_err(|_| PrecompileError::InvalidSignature)?; - - // Define curve group - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1) - .map_err(|_| PrecompileError::InvalidSignature)?; - let mut ctx = BigNumContext::new().map_err(|_| PrecompileError::InvalidSignature)?; - - for i in 0..num_signatures { - let start = i - .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) - .saturating_add(SIGNATURE_OFFSETS_START); - let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE); - - // bytemuck wants structures aligned - let offsets: &Secp256r1SignatureOffsets = - bytemuck::try_from_bytes(&data[start..end]) - .map_err(|_| PrecompileError::InvalidDataOffsets)?; - - // Parse out signature - let signature = get_data_slice( - data, - instruction_datas, - offsets.signature_instruction_index, - offsets.signature_offset, - SIGNATURE_SERIALIZED_SIZE, - )?; - - // Parse out pubkey - let pubkey = get_data_slice( - data, - instruction_datas, - offsets.public_key_instruction_index, - offsets.public_key_offset, - COMPRESSED_PUBKEY_SERIALIZED_SIZE, - )?; - - // Parse out message - let message = get_data_slice( - data, - instruction_datas, - offsets.message_instruction_index, - offsets.message_data_offset, - offsets.message_data_size as usize, - )?; - - let r_bignum = BigNum::from_slice(&signature[..FIELD_SIZE]) - .map_err(|_| PrecompileError::InvalidSignature)?; - let s_bignum = BigNum::from_slice(&signature[FIELD_SIZE..]) - .map_err(|_| PrecompileError::InvalidSignature)?; - - // Check that the signature is generally in range - let within_range = r_bignum >= one - && r_bignum <= order_minus_one - && s_bignum >= one - && s_bignum <= half_order; - - if !within_range { - return Err(PrecompileError::InvalidSignature); - } - - // Create an ECDSA signature object from the ASN.1 integers - let ecdsa_sig = openssl::ecdsa::EcdsaSig::from_private_components(r_bignum, s_bignum) - .and_then(|sig| sig.to_der()) - .map_err(|_| PrecompileError::InvalidSignature)?; - - let public_key_point = EcPoint::from_bytes(&group, pubkey, &mut ctx) - .map_err(|_| PrecompileError::InvalidPublicKey)?; - let public_key = EcKey::from_public_key(&group, &public_key_point) - .map_err(|_| PrecompileError::InvalidPublicKey)?; - let public_key_as_pkey = - PKey::from_ec_key(public_key).map_err(|_| PrecompileError::InvalidPublicKey)?; - - let mut verifier = - Verifier::new(openssl::hash::MessageDigest::sha256(), &public_key_as_pkey) - .map_err(|_| PrecompileError::InvalidSignature)?; - verifier - .update(message) - .map_err(|_| PrecompileError::InvalidSignature)?; - - if !verifier - .verify(&ecdsa_sig) - .map_err(|_| PrecompileError::InvalidSignature)? - { - return Err(PrecompileError::InvalidSignature); - } - } - Ok(()) - } - - fn get_data_slice<'a>( - data: &'a [u8], - instruction_datas: &'a [&[u8]], - instruction_index: u16, - offset_start: u16, - size: usize, - ) -> Result<&'a [u8], PrecompileError> { - let instruction = if instruction_index == u16::MAX { - data - } else { - let signature_index = instruction_index as usize; - if signature_index >= instruction_datas.len() { - return Err(PrecompileError::InvalidDataOffsets); - } - instruction_datas[signature_index] - }; - - let start = offset_start as usize; - let end = start.saturating_add(size); - if end > instruction.len() { - return Err(PrecompileError::InvalidDataOffsets); - } - - Ok(&instruction[start..end]) - } - - #[cfg(test)] - #[allow(deprecated)] - mod test { - use { - super::*, - solana_feature_set::FeatureSet, - solana_sdk::{ - hash::Hash, - signature::{Keypair, Signer}, - transaction::Transaction, - }, - }; - - fn test_case( - num_signatures: u16, - offsets: &Secp256r1SignatureOffsets, - ) -> Result<(), PrecompileError> { - assert_eq!( - bytemuck::bytes_of(offsets).len(), - SIGNATURE_OFFSETS_SERIALIZED_SIZE - ); - - let mut instruction_data = vec![0u8; DATA_START]; - instruction_data[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&num_signatures)); - instruction_data[SIGNATURE_OFFSETS_START..DATA_START] - .copy_from_slice(bytes_of(offsets)); - verify( - &instruction_data, - &[&[0u8; 100]], - &FeatureSet::all_enabled(), - ) - } - - #[test] - fn test_invalid_offsets() { - solana_logger::setup(); - - let mut instruction_data = vec![0u8; DATA_START]; - let offsets = Secp256r1SignatureOffsets::default(); - instruction_data[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&1u16)); - instruction_data[SIGNATURE_OFFSETS_START..DATA_START] - .copy_from_slice(bytes_of(&offsets)); - instruction_data.truncate(instruction_data.len() - 1); - - assert_eq!( - verify( - &instruction_data, - &[&[0u8; 100]], - &FeatureSet::all_enabled() - ), - Err(PrecompileError::InvalidInstructionDataSize) - ); - - let offsets = Secp256r1SignatureOffsets { - signature_instruction_index: 1, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Secp256r1SignatureOffsets { - message_instruction_index: 1, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Secp256r1SignatureOffsets { - public_key_instruction_index: 1, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_invalid_signature_data_size() { - solana_logger::setup(); - - // Test data.len() < SIGNATURE_OFFSETS_START - let small_data = vec![0u8; SIGNATURE_OFFSETS_START - 1]; - assert_eq!( - verify(&small_data, &[&[]], &FeatureSet::all_enabled()), - Err(PrecompileError::InvalidInstructionDataSize) - ); - - // Test num_signatures == 0 - let mut zero_sigs_data = vec![0u8; DATA_START]; - zero_sigs_data[0] = 0; // Set num_signatures to 0 - assert_eq!( - verify(&zero_sigs_data, &[&[]], &FeatureSet::all_enabled()), - Err(PrecompileError::InvalidInstructionDataSize) - ); - - // Test num_signatures > 8 - let mut too_many_sigs = vec![0u8; DATA_START]; - too_many_sigs[0] = 9; // Set num_signatures to 9 - assert_eq!( - verify(&too_many_sigs, &[&[]], &FeatureSet::all_enabled()), - Err(PrecompileError::InvalidInstructionDataSize) - ); - } - #[test] - fn test_message_data_offsets() { - let offsets = Secp256r1SignatureOffsets { - message_data_offset: 99, - message_data_size: 1, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidSignature) - ); - - let offsets = Secp256r1SignatureOffsets { - message_data_offset: 100, - message_data_size: 1, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Secp256r1SignatureOffsets { - message_data_offset: 100, - message_data_size: 1000, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Secp256r1SignatureOffsets { - message_data_offset: u16::MAX, - message_data_size: u16::MAX, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_pubkey_offset() { - let offsets = Secp256r1SignatureOffsets { - public_key_offset: u16::MAX, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Secp256r1SignatureOffsets { - public_key_offset: 100 - (COMPRESSED_PUBKEY_SERIALIZED_SIZE as u16) + 1, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_signature_offset() { - let offsets = Secp256r1SignatureOffsets { - signature_offset: u16::MAX, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - - let offsets = Secp256r1SignatureOffsets { - signature_offset: 100 - (SIGNATURE_SERIALIZED_SIZE as u16) + 1, - ..Secp256r1SignatureOffsets::default() - }; - assert_eq!( - test_case(1, &offsets), - Err(PrecompileError::InvalidDataOffsets) - ); - } - - #[test] - fn test_secp256r1() { - solana_logger::setup(); - let message_arr = b"hello"; - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let signing_key = EcKey::generate(&group).unwrap(); - - let signature = - sign_message(message_arr, &signing_key.private_key_to_der().unwrap()).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let pubkey = signing_key - .public_key() - .to_bytes( - &group, - openssl::ec::PointConversionForm::COMPRESSED, - &mut ctx, - ) - .unwrap(); - assert_eq!(pubkey.len(), COMPRESSED_PUBKEY_SERIALIZED_SIZE); - let mut instruction = new_secp256r1_instruction_with_signature( - message_arr, - &signature, - &pubkey.try_into().unwrap(), - ); - let mint_keypair = Keypair::new(); - let feature_set = FeatureSet::all_enabled(); - - let tx = Transaction::new_signed_with_payer( - &[instruction.clone()], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - - assert!(tx.verify_precompiles(&feature_set).is_ok()); - - // The message is the last field in the instruction data so - // changing its last byte will also change the signature validity - let message_byte_index = instruction.data.len() - 1; - instruction.data[message_byte_index] = - instruction.data[message_byte_index].wrapping_add(12); - let tx = Transaction::new_signed_with_payer( - &[instruction.clone()], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - - assert!(tx.verify_precompiles(&feature_set).is_err()); - } - - #[test] - fn test_secp256r1_high_s() { - solana_logger::setup(); - let message_arr = b"hello"; - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let signing_key = EcKey::generate(&group).unwrap(); - let signature = - sign_message(message_arr, &signing_key.private_key_to_der().unwrap()).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let pubkey = signing_key - .public_key() - .to_bytes( - &group, - openssl::ec::PointConversionForm::COMPRESSED, - &mut ctx, - ) - .unwrap(); - assert_eq!(pubkey.len(), COMPRESSED_PUBKEY_SERIALIZED_SIZE); - let mut instruction = new_secp256r1_instruction_with_signature( - message_arr, - &signature, - &pubkey.try_into().unwrap(), - ); - - // To double check that the untampered low-S value signature passes - let feature_set = FeatureSet::all_enabled(); - let tx_pass = verify( - instruction.data.as_slice(), - &[instruction.data.as_slice()], - &feature_set, - ); - assert!(tx_pass.is_ok()); - - // Determine offsets at which to perform the S-value manipulation - let public_key_offset = DATA_START; - let signature_offset = public_key_offset + COMPRESSED_PUBKEY_SERIALIZED_SIZE; - let s_offset = signature_offset + FIELD_SIZE; - - // Create a high S value by doing order - s - let order = BigNum::from_slice(&SECP256R1_ORDER).unwrap(); - let current_s = - BigNum::from_slice(&instruction.data[s_offset..s_offset + FIELD_SIZE]).unwrap(); - let mut high_s = BigNum::new().unwrap(); - high_s.checked_sub(&order, ¤t_s).unwrap(); - - // Replace the S value in the signature with our high S - instruction.data[s_offset..s_offset + FIELD_SIZE].copy_from_slice(&high_s.to_vec()); - - // Since Transaction::verify_precompiles only returns a vague - // `InvalidAccountIndex` error on precompile failure, we use verify() - // here directly to check for the specific - // InvalidSignatureValueRange error - let tx_fail = verify( - instruction.data.as_slice(), - &[instruction.data.as_slice()], - &feature_set, - ); - assert!(tx_fail.unwrap_err() == PrecompileError::InvalidSignature); - } - #[test] - fn test_new_secp256r1_instruction_31byte_components() { - solana_logger::setup(); - let message_arr = b"hello"; - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let signing_key = EcKey::generate(&group).unwrap(); - - // Keep generating signatures until we get one with a 31-byte component - loop { - let signature = - sign_message(message_arr, &signing_key.private_key_to_der().unwrap()).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let pubkey = signing_key - .public_key() - .to_bytes( - &group, - openssl::ec::PointConversionForm::COMPRESSED, - &mut ctx, - ) - .unwrap(); - assert_eq!(pubkey.len(), COMPRESSED_PUBKEY_SERIALIZED_SIZE); - let instruction = new_secp256r1_instruction_with_signature( - message_arr, - &signature, - &pubkey.try_into().unwrap(), - ); - - // Extract r and s from the signature - let signature_offset = DATA_START + COMPRESSED_PUBKEY_SERIALIZED_SIZE; - let r = &instruction.data[signature_offset..signature_offset + FIELD_SIZE]; - let s = &instruction.data - [signature_offset + FIELD_SIZE..signature_offset + 2 * FIELD_SIZE]; - - // Convert to BigNum and back to get byte representation - let r_bn = BigNum::from_slice(r).unwrap(); - let s_bn = BigNum::from_slice(s).unwrap(); - let r_bytes = r_bn.to_vec(); - let s_bytes = s_bn.to_vec(); - - if r_bytes.len() == 31 || s_bytes.len() == 31 { - // Once found, verify the signature and break out of the loop - let mint_keypair = Keypair::new(); - let tx = Transaction::new_signed_with_payer( - &[instruction], - Some(&mint_keypair.pubkey()), - &[&mint_keypair], - Hash::default(), - ); - - let feature_set = FeatureSet::all_enabled(); - assert!(tx.verify_precompiles(&feature_set).is_ok()); - break; - } - } - } - - #[test] - fn test_new_secp256r1_instruction_signing_key() { - solana_logger::setup(); - let message_arr = b"hello"; - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let signing_key = EcKey::generate(&group).unwrap(); - - let _ = sign_message(message_arr, &signing_key.private_key_to_der().unwrap()).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let pubkey = signing_key - .public_key() - .to_bytes( - &group, - openssl::ec::PointConversionForm::COMPRESSED, - &mut ctx, - ) - .unwrap(); - assert_eq!(pubkey.len(), COMPRESSED_PUBKEY_SERIALIZED_SIZE); - - let incorrect_group = EcGroup::from_curve_name(Nid::X9_62_PRIME192V1).unwrap(); - let incorrect_key = EcKey::generate(&incorrect_group).unwrap(); - assert!( - sign_message(message_arr, &incorrect_key.private_key_to_der().unwrap()).is_err() - ); - } - #[test] - fn test_secp256r1_order() { - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let mut openssl_order = BigNum::new().unwrap(); - group.order(&mut openssl_order, &mut ctx).unwrap(); - - let our_order = BigNum::from_slice(&SECP256R1_ORDER).unwrap(); - assert_eq!(our_order, openssl_order); - } - - #[test] - fn test_secp256r1_order_minus_one() { - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let mut openssl_order = BigNum::new().unwrap(); - group.order(&mut openssl_order, &mut ctx).unwrap(); - - let mut expected_order_minus_one = BigNum::new().unwrap(); - expected_order_minus_one - .checked_sub(&openssl_order, &BigNum::from_u32(1).unwrap()) - .unwrap(); - - let our_order_minus_one = BigNum::from_slice(&SECP256R1_ORDER_MINUS_ONE).unwrap(); - assert_eq!(our_order_minus_one, expected_order_minus_one); - } - - #[test] - fn test_secp256r1_half_order() { - // Get the secp256r1 curve group - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - - // Get the order from OpenSSL - let mut ctx = BigNumContext::new().unwrap(); - let mut openssl_order = BigNum::new().unwrap(); - group.order(&mut openssl_order, &mut ctx).unwrap(); - - // Calculate half order - let mut calculated_half_order = BigNum::new().unwrap(); - let two = BigNum::from_u32(2).unwrap(); - calculated_half_order - .checked_div(&openssl_order, &two, &mut ctx) - .unwrap(); - - // Get our constant half order - let our_half_order = BigNum::from_slice(&SECP256R1_HALF_ORDER).unwrap(); - - // Compare the calculated half order with our constant - assert_eq!(calculated_half_order, our_half_order); - } - - #[test] - fn test_secp256r1_order_relationships() { - let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let mut openssl_order = BigNum::new().unwrap(); - group.order(&mut openssl_order, &mut ctx).unwrap(); - - let our_order = BigNum::from_slice(&SECP256R1_ORDER).unwrap(); - let our_order_minus_one = BigNum::from_slice(&SECP256R1_ORDER_MINUS_ONE).unwrap(); - let our_half_order = BigNum::from_slice(&SECP256R1_HALF_ORDER).unwrap(); - - // Verify our order matches OpenSSL's order - assert_eq!(our_order, openssl_order); - - // Verify order - 1 - let mut expected_order_minus_one = BigNum::new().unwrap(); - expected_order_minus_one - .checked_sub(&openssl_order, &BigNum::from_u32(1).unwrap()) - .unwrap(); - assert_eq!(our_order_minus_one, expected_order_minus_one); - - // Verify half order - let mut expected_half_order = BigNum::new().unwrap(); - expected_half_order - .checked_div(&openssl_order, &BigNum::from_u32(2).unwrap(), &mut ctx) - .unwrap(); - assert_eq!(our_half_order, expected_half_order); - - // Verify half order * 2 = order - 1 - let mut double_half_order = BigNum::new().unwrap(); - double_half_order - .checked_mul(&our_half_order, &BigNum::from_u32(2).unwrap(), &mut ctx) - .unwrap(); - assert_eq!(double_half_order, expected_order_minus_one); - } - } -} - -#[cfg(any(target_arch = "wasm32", target_os = "solana"))] -mod target_arch { - use solana_precompile_error::PrecompileError; - - #[deprecated( - since = "2.2.4", - note = "Use agave_precompiles::secp256r1::verify instead" - )] - #[allow(deprecated)] - pub fn verify( - _data: &[u8], - _instruction_datas: &[&[u8]], - _feature_set: &solana_feature_set::FeatureSet, - ) -> Result<(), PrecompileError> { - Err(PrecompileError::InvalidSignature) - } } pub use self::target_arch::*; diff --git a/seed-phrase/Cargo.toml b/seed-phrase/Cargo.toml index 3a367dc93..60268cc24 100644 --- a/seed-phrase/Cargo.toml +++ b/seed-phrase/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-seed-phrase" description = "Solana functions for generating keypairs from seed phrases." documentation = "https://docs.rs/solana-seed-phrase" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/serde/Cargo.toml b/serde/Cargo.toml index d5c0f2c9c..ebe60a4b6 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-serde" description = "Solana serde helpers" documentation = "https://docs.rs/solana-serde" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/serialize-utils/Cargo.toml b/serialize-utils/Cargo.toml index e29090c52..071e1903c 100644 --- a/serialize-utils/Cargo.toml +++ b/serialize-utils/Cargo.toml @@ -13,9 +13,7 @@ edition = { workspace = true } targets = ["x86_64-unknown-linux-gnu"] [dependencies] -solana-instruction = { workspace = true, default-features = false, features = [ - "std", -] } +solana-instruction-error = { workspace = true } solana-pubkey = { workspace = true, default-features = false } solana-sanitize = { workspace = true } diff --git a/serialize-utils/src/cursor.rs b/serialize-utils/src/cursor.rs index 5e4639281..e2a49576e 100644 --- a/serialize-utils/src/cursor.rs +++ b/serialize-utils/src/cursor.rs @@ -1,5 +1,5 @@ use { - solana_instruction::error::InstructionError, + solana_instruction_error::InstructionError, solana_pubkey::{Pubkey, PUBKEY_BYTES}, std::{ io::{BufRead as _, Cursor, Read}, diff --git a/sha256-hasher/Cargo.toml b/sha256-hasher/Cargo.toml index 5951e38f5..17d278c13 100644 --- a/sha256-hasher/Cargo.toml +++ b/sha256-hasher/Cargo.toml @@ -19,14 +19,13 @@ sha2 = ["dep:sha2"] solana-hash = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] -sha2 = { workspace = true } +sha2 = { workspace = true, optional = true } [target.'cfg(target_os = "solana")'.dependencies] -# sha2 should be removed in the next breaking release, -# as there's no reason to use the crate instead of the syscall -# onchain -sha2 = { workspace = true, optional = true } solana-define-syscall = { workspace = true } +[dev-dependencies] +solana-sha256-hasher = { path = ".", features = ["sha2"] } + [lints] workspace = true diff --git a/sha256-hasher/src/lib.rs b/sha256-hasher/src/lib.rs index 04c71d918..e87857302 100644 --- a/sha256-hasher/src/lib.rs +++ b/sha256-hasher/src/lib.rs @@ -1,15 +1,15 @@ #![no_std] -#[cfg(any(feature = "sha2", not(target_os = "solana")))] +#[cfg(all(feature = "sha2", not(target_os = "solana")))] use sha2::{Digest, Sha256}; use solana_hash::Hash; -#[cfg(any(feature = "sha2", not(target_os = "solana")))] +#[cfg(all(feature = "sha2", not(target_os = "solana")))] #[derive(Clone, Default)] pub struct Hasher { hasher: Sha256, } -#[cfg(any(feature = "sha2", not(target_os = "solana")))] +#[cfg(all(feature = "sha2", not(target_os = "solana")))] impl Hasher { pub fn hash(&mut self, val: &[u8]) { self.hasher.update(val); @@ -34,9 +34,17 @@ pub fn hashv(vals: &[&[u8]]) -> Hash { // not supported #[cfg(not(target_os = "solana"))] { - let mut hasher = Hasher::default(); - hasher.hashv(vals); - hasher.result() + #[cfg(feature = "sha2")] + { + let mut hasher = Hasher::default(); + hasher.hashv(vals); + hasher.result() + } + #[cfg(not(feature = "sha2"))] + { + core::hint::black_box(vals); + panic!("hashv is only available on target `solana` or with the `sha2` feature enabled on this crate") + } } // Call via a system call to perform the calculation #[cfg(target_os = "solana")] @@ -57,10 +65,3 @@ pub fn hashv(vals: &[&[u8]]) -> Hash { pub fn hash(val: &[u8]) -> Hash { hashv(&[val]) } - -/// Return the hash of the given hash extended with the given value. -pub fn extend_and_hash(id: &Hash, val: &[u8]) -> Hash { - let mut hash_data = id.as_ref().to_vec(); - hash_data.extend_from_slice(val); - hash(&hash_data) -} diff --git a/shred-version/src/lib.rs b/shred-version/src/lib.rs index 6d44cc745..9eb8293a0 100644 --- a/shred-version/src/lib.rs +++ b/shred-version/src/lib.rs @@ -2,7 +2,7 @@ //! //! [shred]: https://solana.com/docs/terminology#shred -use {solana_hard_forks::HardForks, solana_hash::Hash, solana_sha256_hasher::extend_and_hash}; +use {solana_hard_forks::HardForks, solana_hash::Hash, solana_sha256_hasher::hashv}; pub fn version_from_hash(hash: &Hash) -> u16 { let hash = hash.as_ref(); @@ -27,7 +27,7 @@ pub fn compute_shred_version(genesis_hash: &Hash, hard_forks: Option<&HardForks> if let Some(hard_forks) = hard_forks { for &(slot, count) in hard_forks.iter() { let buf = [slot.to_le_bytes(), (count as u64).to_le_bytes()].concat(); - hash = extend_and_hash(&hash, &buf); + hash = hashv(&[hash.as_ref(), &buf]); } } diff --git a/signature/Cargo.toml b/signature/Cargo.toml index 0bb400182..e84e189fb 100644 --- a/signature/Cargo.toml +++ b/signature/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-signature" description = "Solana 64-byte signature type" documentation = "https://docs.rs/solana-signature" version = "2.3.0" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/signature/src/error.rs b/signature/src/error.rs index 1ae6fb50f..ff96051dd 100644 --- a/signature/src/error.rs +++ b/signature/src/error.rs @@ -1,7 +1,7 @@ -//! Signature error copied directly from RustCrypto's opaque signature error at -//! https://github.com/RustCrypto/traits/tree/master/signature +//! Signature error copied directly from +//! [RustCrypto's opaque signature error](https://github.com/RustCrypto/traits/tree/master/signature) -#[cfg(all(feature = "std", feature = "alloc"))] +#[cfg(feature = "alloc")] use alloc::boxed::Box; use core::fmt::{self, Debug, Display}; @@ -11,19 +11,21 @@ use core::fmt::{self, Debug, Display}; /// could potentially be used recover signing private keys or forge signatures /// (e.g. [BB'06]). /// -/// When the `std` feature is enabled, it impls [`std::error::Error`]. +/// When the `std` feature is enabled, it impls +/// [`core::error::Error`](https://doc.rust-lang.org/core/error/trait.Error.html). /// /// When the `alloc` feature is enabled, it supports an optional -/// [`std::error::Error::source`], which can be used by things like remote -/// signers (e.g. HSM, KMS) to report I/O or auth errors. +/// [`core::error::Error::source`](https://doc.rust-lang.org/core/error/trait.Error.html#method.source), +/// which can be used by things like remote signers (e.g. HSM, KMS) to report +/// I/O or auth errors. /// /// [BB'06]: https://en.wikipedia.org/wiki/Daniel_Bleichenbacher #[derive(Default)] #[non_exhaustive] pub struct Error { /// Source of the error (if applicable). - #[cfg(all(feature = "std", feature = "alloc"))] - source: Option>, + #[cfg(feature = "alloc")] + source: Option>, } impl Error { @@ -33,9 +35,9 @@ impl Error { /// errors e.g. signature parsing or verification errors. The intended use /// cases are for propagating errors related to external signers, e.g. /// communication/authentication errors with HSMs, KMS, etc. - #[cfg(all(feature = "std", feature = "alloc"))] + #[cfg(feature = "alloc")] pub fn from_source( - source: impl Into>, + source: impl Into>, ) -> Self { Self { source: Some(source.into()), @@ -44,17 +46,17 @@ impl Error { } impl Debug for Error { - #[cfg(not(all(feature = "std", feature = "alloc")))] + #[cfg(not(feature = "alloc"))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("signature::Error {}") } - #[cfg(all(feature = "std", feature = "alloc"))] + #[cfg(feature = "alloc")] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("signature::Error { source: ")?; if let Some(source) = &self.source { - write!(f, "Some({})", source)?; + write!(f, "Some({source})")?; } else { f.write_str("None")?; } @@ -69,18 +71,24 @@ impl Display for Error { } } -#[cfg(all(feature = "std", feature = "alloc"))] -impl From> for Error { - fn from(source: Box) -> Error { +#[cfg(feature = "alloc")] +impl From> for Error { + fn from(source: Box) -> Error { Self::from_source(source) } } -#[cfg(feature = "std")] -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.source - .as_ref() - .map(|source| source.as_ref() as &(dyn std::error::Error + 'static)) +impl core::error::Error for Error { + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + #[cfg(feature = "alloc")] + { + self.source + .as_ref() + .map(|source| source.as_ref() as &(dyn core::error::Error + 'static)) + } + #[cfg(not(feature = "alloc"))] + { + None + } } } diff --git a/signature/src/lib.rs b/signature/src/lib.rs index dfe6c00ad..3fa8eb23e 100644 --- a/signature/src/lib.rs +++ b/signature/src/lib.rs @@ -12,8 +12,9 @@ use core::{ extern crate alloc; #[cfg(feature = "std")] extern crate std; +use core::error::Error; #[cfg(feature = "std")] -use std::{error::Error, vec::Vec}; +use std::vec::Vec; #[cfg(feature = "serde")] use { serde_big_array::BigArray, @@ -65,7 +66,7 @@ impl Signature { pubkey_bytes: &[u8], message_bytes: &[u8], ) -> Result<(), ed25519_dalek::SignatureError> { - let publickey = ed25519_dalek::PublicKey::from_bytes(pubkey_bytes)?; + let publickey = ed25519_dalek::VerifyingKey::try_from(pubkey_bytes)?; let signature = self.0.as_slice().try_into()?; publickey.verify_strict(message_bytes, &signature) } @@ -139,7 +140,6 @@ pub enum ParseSignatureError { Invalid, } -#[cfg(feature = "std")] impl Error for ParseSignatureError {} impl fmt::Display for ParseSignatureError { diff --git a/signer-store/Cargo.toml b/signer-store/Cargo.toml new file mode 100644 index 000000000..807a60207 --- /dev/null +++ b/signer-store/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "solana-signer-store" +description = "Solana Signer Store" +documentation = "https://docs.rs/solana-signer-store" +version = "0.1.0" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[dependencies] +bitvec = { workspace = true } +num-derive = { workspace = true } +num-traits = { workspace = true } + +[dev-dependencies] +criterion = { workspace = true } +rand = { workspace = true } + +[lints] +workspace = true + +[[bench]] +name = "encoding" +harness = false diff --git a/signer-store/benches/encoding.rs b/signer-store/benches/encoding.rs new file mode 100644 index 000000000..5ec5bbcdf --- /dev/null +++ b/signer-store/benches/encoding.rs @@ -0,0 +1,116 @@ +use { + bitvec::prelude::*, + criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}, + rand::{rngs::ThreadRng, Rng}, + solana_signer_store::{decode, encode_base2, encode_base3, Decoded}, + std::iter, +}; + +/// Creates a single BitVec with pseudo-random data for Base2 benchmarking. +fn create_test_data_base2(rng: &mut ThreadRng, len: usize) -> BitVec { + iter::repeat_with(|| rng.gen_bool(0.5)).take(len).collect() +} + +/// Creates two BitVecs with a uniform distribution of valid Base3 pairs. +fn create_test_data_base3_uniform(len: usize) -> (BitVec, BitVec) { + let mut base = BitVec::with_capacity(len); + let mut fallback = BitVec::with_capacity(len); + for i in 0..len { + match i % 3 { + 0 => { + base.push(false); + fallback.push(false); + } + 1 => { + base.push(true); + fallback.push(false); + } + _ => { + base.push(false); + fallback.push(true); + } + } + } + (base, fallback) +} + +/// Creates two sparse BitVecs, where most pairs are (false, false). +fn create_test_data_base3_sparse(len: usize) -> (BitVec, BitVec) { + let mut base = BitVec::with_capacity(len); + let mut fallback = BitVec::with_capacity(len); + for i in 0..len { + // ~10% chance of being non-zero + if i % 10 == 1 { + base.push(true); + fallback.push(false); + } else { + base.push(false); + fallback.push(false); + } + } + (base, fallback) +} + +/// Benchmarks the Base2 encoding scheme. +fn bench_base2(c: &mut Criterion) { + let mut group = c.benchmark_group("Base2_Encoding"); + let mut rng = rand::thread_rng(); + + for size in [256, 512, 1024, 2048, 4096, 8192].iter() { + let bit_vec = create_test_data_base2(&mut rng, *size); + let encoded = encode_base2(&bit_vec).unwrap(); + + group.bench_with_input(BenchmarkId::new("encode", size), size, |b, _| { + b.iter(|| encode_base2(&bit_vec).unwrap()); + }); + + group.bench_with_input(BenchmarkId::new("decode", size), size, |b, _| { + b.iter(|| { + let decoded = decode(&encoded, *size).unwrap(); + assert!(matches!(decoded, Decoded::Base2(_))); + }); + }); + } + group.finish(); +} + +/// Benchmarks the Base3 encoding scheme. +fn bench_base3(c: &mut Criterion) { + let mut group = c.benchmark_group("Base3_Encoding"); + + for size in [256, 512, 1024, 2048, 4096, 8192].iter() { + // Benchmark for standard, uniformly distributed data + let (base, fallback) = create_test_data_base3_uniform(*size); + let encoded = encode_base3(&base, &fallback).unwrap(); + + group.bench_with_input(BenchmarkId::new("encode_uniform", size), size, |b, _| { + b.iter(|| encode_base3(&base, &fallback).unwrap()); + }); + + group.bench_with_input(BenchmarkId::new("decode_uniform", size), size, |b, _| { + b.iter(|| { + let decoded = decode(&encoded, *size).unwrap(); + assert!(matches!(decoded, Decoded::Base3(_, _))); + }); + }); + + // Benchmark for sparse data + let (base_sparse, fallback_sparse) = create_test_data_base3_sparse(*size); + let encoded_sparse = encode_base3(&base_sparse, &fallback_sparse).unwrap(); + + group.bench_with_input(BenchmarkId::new("encode_sparse", size), size, |b, _| { + b.iter(|| encode_base3(&base_sparse, &fallback_sparse).unwrap()); + }); + + group.bench_with_input(BenchmarkId::new("decode_sparse", size), size, |b, _| { + b.iter(|| { + let decoded = decode(&encoded_sparse, *size).unwrap(); + assert!(matches!(decoded, Decoded::Base3(_, _))); + }); + }); + } + group.finish(); +} + +criterion_group!(benches, bench_base2, bench_base3); +criterion_main!(benches); diff --git a/signer-store/src/lib.rs b/signer-store/src/lib.rs new file mode 100644 index 000000000..4471bf66f --- /dev/null +++ b/signer-store/src/lib.rs @@ -0,0 +1,419 @@ +//! Provides a space-efficient encoding scheme for one or two boolean vectors, +//! primarily used to compactly encode the set of signers in an aggregate signature. +//! +//! This module implements compression algorithms to encode boolean vectors +//! into a single byte vector (`Vec`). It currently supports two distinct +//! schemes based on the number of input vectors. +//! +//! # Encoding Schemes +//! +//! ## Base2 Encoding (Single Vector) +//! When a single boolean vector is provided, it is encoded directly. +//! The format is: +//! 1. **Version Byte (1 byte)**: `Version::Base2` as a `u8`. +//! 2. **Length Prefix (2 bytes)**: A `u16` in little-endian format storing the +//! original number of bits in the input vector (not length of the final +//! vector). +//! 3. **Data Payload**: The raw byte data of the boolean vector. +//! +//! ## Base3 Encoding (Two Vectors) +//! When two boolean vectors of the same length are provided, they are compressed +//! together. This scheme assumes that for any given index, the bits in both +//! vectors will not both be `1`. +//! +//! The pairs of booleans are mapped to a single ternary (base-3) digit: +//! - `(false, false)` -> `0` +//! - `(true, false)` -> `1` +//! - `(false, true)` -> `2` +//! +//! The combination `(true, true)` is considered invalid. These ternary digits are +//! packed five at a time into a single `u8`, since `3^5 < 2^8`. +//! +//! The format is: +//! 1. **Version Byte (1 byte)**: `Version::Base3` as a `u8`. +//! 2. **Length Prefix (2 bytes)**: A `u16` in little-endian format storing the +//! original number of bits (i.e., the length of the input vectors; not the +//! length of the final vector). +//! 3. **Data Payload**: A sequence of bytes containing the packed base-3 digits. + +use { + bitvec::prelude::*, + num_derive::{FromPrimitive, ToPrimitive}, + num_traits::FromPrimitive, +}; + +const VERSION_BYTE_LEN: usize = 1; +const LENGTH_PREFIX_LEN: usize = 2; +const HEADER_LEN: usize = VERSION_BYTE_LEN + LENGTH_PREFIX_LEN; + +/// Represents the encoding version, used as the first byte in the output. +#[derive(Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)] +#[repr(u8)] +pub enum Version { + Base2 = 0, + Base3 = 1, +} + +/// An error that can occur during the encoding process. +#[derive(Debug, PartialEq, Eq)] +pub enum EncodeError { + /// In Base3 encoding, the provided bit-vectors have unmatching lengths. + MismatchedLengths, + /// In Base3 encoding, the invalid combination `(true, true)` was found. + InvalidBitCombination, + /// The length of the input vectors exceeds `u16::MAX` (65,535). + LengthExceedsLimit, + /// An arithmetic operation resulted in an overflow. + ArithmeticOverflow, +} + +// Each u8 can hold 5 base-3 symbols (3^5 = 243). +const BASE3_SYMBOLS_PER_BYTE: usize = 5; + +/// Encodes a single boolean vector using Base2 encoding. +/// +/// The output `Vec` is prefixed with the `Version::Base2` byte. +pub fn encode_base2(bit_vec: &BitVec) -> Result, EncodeError> { + let num_bits = bit_vec.len(); + if num_bits > u16::MAX as usize { + return Err(EncodeError::LengthExceedsLimit); + } + + let raw_slice = bit_vec.as_raw_slice(); + let capacity = HEADER_LEN + .checked_add(raw_slice.len()) + .ok_or(EncodeError::ArithmeticOverflow)?; + let mut result = Vec::with_capacity(capacity); + result.push(Version::Base2 as u8); + result.extend_from_slice(&(num_bits as u16).to_le_bytes()); + result.extend_from_slice(raw_slice); + + Ok(result) +} + +/// Encodes two boolean vectors using Base3 encoding. +/// +/// This function assumes that for any given index, `bit_vec_base` and +/// `bit_vec_fallback` will not both have a bit set to `1`. +/// The output `Vec` is prefixed with the `Version::Base3` byte. +pub fn encode_base3( + bit_vec_base: &BitVec, + bit_vec_fallback: &BitVec, +) -> Result, EncodeError> { + if bit_vec_base.len() != bit_vec_fallback.len() { + return Err(EncodeError::MismatchedLengths); + } + let num_bits = bit_vec_base.len(); + if num_bits > u16::MAX as usize { + return Err(EncodeError::LengthExceedsLimit); + } + + let base_bytes = bit_vec_base.as_raw_slice(); + let fallback_bytes = bit_vec_fallback.as_raw_slice(); + + let num_chunks = num_bits.div_ceil(BASE3_SYMBOLS_PER_BYTE); + let capacity = HEADER_LEN + .checked_add(num_chunks) + .ok_or(EncodeError::ArithmeticOverflow)?; + let mut result = Vec::with_capacity(capacity); + + result.push(Version::Base3 as u8); + result.extend_from_slice(&(num_bits as u16).to_le_bytes()); + + for chunk_index in 0..num_chunks { + let mut block_num: u8 = 0; + let start_bit = chunk_index + .checked_mul(BASE3_SYMBOLS_PER_BYTE) + .ok_or(EncodeError::ArithmeticOverflow)?; + let end_bit = start_bit + .checked_add(BASE3_SYMBOLS_PER_BYTE) + .ok_or(EncodeError::ArithmeticOverflow)? + .min(num_bits); + + // Process bits in reverse order to simplify packing + for i in (start_bit..end_bit).rev() { + let byte_idx = i / 8; + let bit_idx = i % 8; + + let base_bit = (base_bytes.get(byte_idx).unwrap_or(&0) >> bit_idx) & 1 == 1; + let fallback_bit = (fallback_bytes.get(byte_idx).unwrap_or(&0) >> bit_idx) & 1 == 1; + + let chunk_num = match (base_bit, fallback_bit) { + (false, false) => 0u8, + (true, false) => 1u8, + (false, true) => 2u8, + (true, true) => return Err(EncodeError::InvalidBitCombination), + }; + + block_num = block_num + .checked_mul(3) + .and_then(|n| n.checked_add(chunk_num)) + .ok_or(EncodeError::ArithmeticOverflow)?; + } + result.push(block_num); + } + Ok(result) +} + +/// Represents the result of a decoding operation. +#[derive(Debug, PartialEq, Eq)] +pub enum Decoded { + /// A single vector from Base2 decoding. + Base2(BitVec), + /// Two vectors from Base3 decoding. + Base3(BitVec, BitVec), +} + +/// An error that can occur during the decoding process. +#[derive(Debug, PartialEq, Eq)] +pub enum DecodeError { + /// The input slice is too short to be valid. + InputTooShort, + /// The encoding version byte is unsupported. + UnsupportedEncoding, + /// The data payload is not of the expected length. + CorruptDataPayload, + /// An arithmetic operation resulted in an overflow. + ArithmeticOverflow, +} + +/// Decodes an encoded byte slice into one or two boolean vectors. +/// +/// It reads the first byte to determine the encoding scheme and then decodes +/// the rest of the data accordingly. +pub fn decode(bytes: &[u8], max_len: usize) -> Result { + if bytes.len() < 3 { + // Must have at least version (1) + length (2) + return Err(DecodeError::InputTooShort); + } + + let version_byte = bytes[0]; + let version = Version::from_u8(version_byte).ok_or(DecodeError::UnsupportedEncoding)?; + + let mut len_arr = [0u8; 2]; + len_arr.copy_from_slice(&bytes[1..3]); + let total_bits = u16::from_le_bytes(len_arr) as usize; + + if total_bits > max_len { + return Err(DecodeError::CorruptDataPayload); + } + + let data_bytes = &bytes[3..]; + + match version { + Version::Base2 => decode_impl_base2(data_bytes, total_bits), + Version::Base3 => decode_impl_base3(data_bytes, total_bits), + } +} + +// Internal function to handle Base2 decoding logic +fn decode_impl_base2(data_bytes: &[u8], total_bits: usize) -> Result { + let expected_byte_len = total_bits.div_ceil(8); + if data_bytes.len() != expected_byte_len { + return Err(DecodeError::CorruptDataPayload); + } + + let mut bit_vec = BitVec::from_slice(data_bytes); + bit_vec.truncate(total_bits); + + Ok(Decoded::Base2(bit_vec)) +} + +// Internal function to handle Base3 decoding logic +fn decode_impl_base3(data_bytes: &[u8], total_bits: usize) -> Result { + let expected_num_chunks = total_bits.div_ceil(BASE3_SYMBOLS_PER_BYTE); + + if data_bytes.len() != expected_num_chunks { + return Err(DecodeError::CorruptDataPayload); + } + + let decoded_byte_len = total_bits.div_ceil(8); + let mut base_bytes = vec![0u8; decoded_byte_len]; + let mut fallback_bytes = vec![0u8; decoded_byte_len]; + + for (chunk_index, &block_byte) in data_bytes.iter().enumerate() { + let mut block_num = block_byte; + let start_bit = chunk_index + .checked_mul(BASE3_SYMBOLS_PER_BYTE) + .ok_or(DecodeError::ArithmeticOverflow)?; + let end_bit = start_bit + .checked_add(BASE3_SYMBOLS_PER_BYTE) + .ok_or(DecodeError::ArithmeticOverflow)? + .min(total_bits); + + for bit_index in start_bit..end_bit { + let remainder = block_num % 3; + block_num /= 3; + + let byte_idx = bit_index / 8; + let bit_idx = bit_index % 8; + + let (base_bit, fallback_bit) = match remainder { + 0 => (false, false), + 1 => (true, false), + 2 => (false, true), + _ => unreachable!(), // Modulo 3 can't be > 2 + }; + + if base_bit { + base_bytes[byte_idx] |= 1 << bit_idx; + } + if fallback_bit { + fallback_bytes[byte_idx] |= 1 << bit_idx; + } + } + } + + let mut base_vec = BitVec::from_vec(base_bytes); + base_vec.truncate(total_bits); + let mut fallback_vec = BitVec::from_vec(fallback_bytes); + fallback_vec.truncate(total_bits); + + Ok(Decoded::Base3(base_vec, fallback_vec)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn create_base3_test_data(len: usize) -> (BitVec, BitVec) { + let mut base = BitVec::with_capacity(len); + let mut fallback = BitVec::with_capacity(len); + for i in 0..len { + match i % 3 { + 0 => { + // (false, false) -> 0 + base.push(false); + fallback.push(false); + } + 1 => { + // (true, false) -> 1 + base.push(true); + fallback.push(false); + } + _ => { + // (false, true) -> 2 + base.push(false); + fallback.push(true); + } + } + } + (base, fallback) + } + + #[test] + fn test_base2_round_trip() { + let original = bitvec![u8, Lsb0; 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1]; + let original_len = original.len(); + let encoded = encode_base2(&original).unwrap(); + + // Check header + assert_eq!(encoded[0], Version::Base2 as u8); // Version byte + assert_eq!( + u16::from_le_bytes(encoded[1..3].try_into().unwrap()), + original_len as u16 + ); + + let decoded = decode(&encoded, original_len).unwrap(); + if let Decoded::Base2(decoded_vec) = decoded { + assert_eq!(original, decoded_vec); + } else { + panic!("Decoded into the wrong type"); + } + } + + #[test] + fn test_base2_empty() { + let original = BitVec::::new(); + let encoded = encode_base2(&original).unwrap(); + assert_eq!(encoded, vec![Version::Base2 as u8, 0, 0]); + let decoded = decode(&encoded, 0).unwrap(); + assert_eq!(decoded, Decoded::Base2(original)); + } + + #[test] + fn test_base3_round_trip() { + let (base, fallback) = create_base3_test_data(23); // Not a multiple of 5 + let original_len = base.len(); + let encoded = encode_base3(&base, &fallback).unwrap(); + + // Check header + assert_eq!(encoded[0], Version::Base3 as u8); // Version byte + assert_eq!( + u16::from_le_bytes(encoded[1..3].try_into().unwrap()), + original_len as u16 + ); + + let decoded = decode(&encoded, original_len).unwrap(); + if let Decoded::Base3(decoded_base, decoded_fallback) = decoded { + assert_eq!(base, decoded_base); + assert_eq!(fallback, decoded_fallback); + } else { + panic!("Decoded into the wrong type"); + } + } + + #[test] + fn test_base3_exact_bytes() { + let (base, fallback) = create_base3_test_data(10); // 2 full bytes + let encoded = encode_base3(&base, &fallback).unwrap(); + let decoded = decode(&encoded, 10).unwrap(); + assert_eq!(decoded, Decoded::Base3(base, fallback)); + } + + #[test] + fn test_base3_empty() { + let (base, fallback) = create_base3_test_data(0); + let encoded = encode_base3(&base, &fallback).unwrap(); + assert_eq!(encoded, vec![Version::Base3 as u8, 0, 0]); + let decoded = decode(&encoded, 0).unwrap(); + assert_eq!(decoded, Decoded::Base3(base, fallback)); + } + + #[test] + fn test_encode_base3_invalid_combination() { + let base = bitvec![u8, Lsb0; 0, 1]; + let fallback = bitvec![u8, Lsb0; 0, 1]; + let result = encode_base3(&base, &fallback); + assert_eq!(result, Err(EncodeError::InvalidBitCombination)); + } + + #[test] + fn test_encode_length_limit() { + let long_vec = BitVec::repeat(false, (u16::MAX as usize) + 1); + let result = encode_base2(&long_vec); + assert_eq!(result, Err(EncodeError::LengthExceedsLimit)); + } + + #[test] + fn test_decode_unsupported_encoding() { + let bytes = vec![2, 0, 0, 1, 2, 3]; // Invalid version byte '2' + let result = decode(&bytes, 10); + assert_eq!(result, Err(DecodeError::UnsupportedEncoding)); + } + + #[test] + fn test_decode_input_too_short() { + let bytes = vec![1, 0]; // Only 2 bytes, needs at least 3 + let result = decode(&bytes, 10); + assert_eq!(result, Err(DecodeError::InputTooShort)); + } + + #[test] + fn test_decode_max_len_exceeded() { + let (base, fallback) = create_base3_test_data(20); + let encoded = encode_base3(&base, &fallback).unwrap(); + // Try to decode with a max_len that is too small + let result = decode(&encoded, 19); + assert_eq!(result, Err(DecodeError::CorruptDataPayload)); + } + + #[test] + fn test_decode_corrupt_payload() { + let (base, fallback) = create_base3_test_data(10); + let mut encoded = encode_base3(&base, &fallback).unwrap(); + encoded.pop(); // Corrupt the payload by removing a byte + let result = decode(&encoded, 10); + assert_eq!(result, Err(DecodeError::CorruptDataPayload)); + } +} diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 12fed1753..abcbb0bc8 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-signer" description = "Abstractions for Solana transaction signers. See `solana-keypair` for a concrete implementation." documentation = "https://docs.rs/solana-signer" version = "2.2.1" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/signer/src/lib.rs b/signer/src/lib.rs index e6c286867..70c45d422 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -22,7 +22,7 @@ pub enum PresignerError { VerificationFailure, } -impl std::error::Error for PresignerError {} +impl core::error::Error for PresignerError {} impl fmt::Display for PresignerError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -49,8 +49,8 @@ pub enum SignerError { TooManySigners, } -impl std::error::Error for SignerError { - fn source(&self) -> ::core::option::Option<&(dyn std::error::Error + 'static)> { +impl core::error::Error for SignerError { + fn source(&self) -> ::core::option::Option<&(dyn core::error::Error + 'static)> { match self { Self::KeypairPubkeyMismatch => None, Self::NotEnoughSigners => None, diff --git a/system-interface/Cargo.toml b/system-interface/Cargo.toml new file mode 100644 index 000000000..eac3abc9a --- /dev/null +++ b/system-interface/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "solana-system-interface" +version = "1.0.0" +description = "Instructions and constructors for the System program" +readme = "README.md" +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } +rust-version = "1.81.0" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +all-features = true +rustdoc-args = ["--cfg=docsrs"] + +[dependencies] +num-traits = { workspace = true } +serde = { workspace = true, optional = true } +serde_derive = { workspace = true, optional = true } +solana-frozen-abi = { workspace = true, features = ["frozen-abi"], optional = true } +solana-frozen-abi-macro = { workspace = true, features = ["frozen-abi"], optional = true } +solana-instruction = { workspace = true, features = ["bincode", "std"], optional = true } +solana-logger = { workspace = true, optional = true } +solana-msg = { workspace = true } +solana-program-error = { workspace = true } +solana-pubkey = { workspace = true, default-features = false } + +[dev-dependencies] +anyhow = { workspace = true } +borsh = { workspace = true, features = ["derive", "unstable__schema"] } +solana-account-info = { workspace = true } +solana-cpi = { path = "../cpi" } +solana-example-mocks = { path = "../example-mocks" } +solana-nonce = { workspace = true } +solana-program-entrypoint = { workspace = true } +solana-program-error = { workspace = true, features = ["borsh"] } +solana-pubkey = { workspace = true, features = ["std"] } +solana-system-interface = { path = ".", features = ["bincode"] } +solana-sysvar = { workspace = true } +solana-sysvar-id = { workspace = true } +static_assertions = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } + +[features] +bincode = ["dep:solana-instruction", "serde"] +frozen-abi = [ + "dep:solana-frozen-abi", + "dep:solana-frozen-abi-macro", + "dep:solana-logger", + "serde", + "solana-pubkey/frozen-abi", + "solana-pubkey/std" +] +serde = ["dep:serde", "dep:serde_derive", "solana-pubkey/serde"] + +[lib] +crate-type = ["rlib"] diff --git a/system-interface/README.md b/system-interface/README.md new file mode 100644 index 000000000..bcf079394 --- /dev/null +++ b/system-interface/README.md @@ -0,0 +1,104 @@ +

+ + Solana + +

+ +# Solana System Interface + +This crate contains instructions and constructors for interacting with the [System program](https://solana.com/docs/core/programs#core-programs). + +The System program can be used to create new accounts, allocate account data, assign accounts to owning programs, transfer lamports from System Program owned accounts and pay transaction fees. + +## Getting Started + +From your project folder: + +```bash +cargo add solana-system-interface --features bincode +``` + +This will add the `solana-system-interface` dependency with the `bincode` feature enabled to your `Cargo.toml` file. The `bincode` feature contains the instruction constructors to create instructions for the System program. + +## Examples + +Creating an account: + +```rust +use solana_rpc_client::rpc_client::RpcClient; +use solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, +}; +use solana_system_interface::instruction; +use anyhow::Result; + +fn create_account( + client: &RpcClient, + payer: &Keypair, + new_account: &Keypair, + owning_program: &Pubkey, + space: u64, +) -> Result<()> { + let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?; + let instr = instruction::create_account( + &payer.pubkey(), + &new_account.pubkey(), + rent, + space, + owning_program, + ); + + let blockhash = client.get_latest_blockhash()?; + let tx = Transaction::new_signed_with_payer( + &[instr], + Some(&payer.pubkey()), + &[payer, new_account], + blockhash, + ); + + let _sig = client.send_and_confirm_transaction(&tx)?; + + Ok(()) +} +``` + +Transfer lamports between accounts: + +```rust +use solana_rpc_client::rpc_client::RpcClient; +use solana_pubkey::Pubkey; +use solana_sdk::{ + signature::{Keypair, Signer}, + transaction::Transaction, +}; +use solana_system_interface::instruction; +use anyhow::Result; + +fn transfer( + client: &RpcClient, + from: &Keypair, + recipient: &Pubkey, + lamports: u64, +) -> Result<()> { + let instr = instruction::transfer( + &from.pubkey(), + recipient, + lamports, + ); + + let blockhash = client.get_latest_blockhash()?; + let tx = Transaction::new_signed_with_payer( + &[instr], + Some(&from.pubkey()), + &[from], + blockhash, + ); + + let _sig = client.send_and_confirm_transaction(&tx)?; + + Ok(()) +} +``` + +More examples can be found on the crate [documentation](https://docs.rs/solana-system-interface/latest/solana-system-interface/). diff --git a/system-interface/src/error.rs b/system-interface/src/error.rs new file mode 100644 index 000000000..2b62de31e --- /dev/null +++ b/system-interface/src/error.rs @@ -0,0 +1,164 @@ +use { + num_traits::{FromPrimitive, ToPrimitive}, + solana_program_error::{ProgramError, ToStr}, +}; + +// Use strum when testing to ensure our FromPrimitive +// impl is exhaustive +#[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))] +#[cfg_attr( + feature = "serde", + derive(serde_derive::Deserialize, serde_derive::Serialize) +)] +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum SystemError { + /// An account with the same address already exists. + AccountAlreadyInUse, + /// Account does not have enough SOL to perform the operation. + ResultWithNegativeLamports, + /// Cannot assign account to this program id. + InvalidProgramId, + /// Cannot allocate account data of this length. + InvalidAccountDataLength, + /// Length of requested seed is too long. + MaxSeedLengthExceeded, + /// Provided address does not match addressed derived from seed. + AddressWithSeedMismatch, + /// Advancing stored nonce requires a populated RecentBlockhashes sysvar. + NonceNoRecentBlockhashes, + /// Stored nonce is still in recent_blockhashes. + NonceBlockhashNotExpired, + /// Specified nonce does not match stored nonce. + NonceUnexpectedBlockhashValue, +} + +impl FromPrimitive for SystemError { + #[inline] + fn from_i64(n: i64) -> Option { + if n == Self::AccountAlreadyInUse as i64 { + Some(Self::AccountAlreadyInUse) + } else if n == Self::ResultWithNegativeLamports as i64 { + Some(Self::ResultWithNegativeLamports) + } else if n == Self::InvalidProgramId as i64 { + Some(Self::InvalidProgramId) + } else if n == Self::InvalidAccountDataLength as i64 { + Some(Self::InvalidAccountDataLength) + } else if n == Self::MaxSeedLengthExceeded as i64 { + Some(Self::MaxSeedLengthExceeded) + } else if n == Self::AddressWithSeedMismatch as i64 { + Some(Self::AddressWithSeedMismatch) + } else if n == Self::NonceNoRecentBlockhashes as i64 { + Some(Self::NonceNoRecentBlockhashes) + } else if n == Self::NonceBlockhashNotExpired as i64 { + Some(Self::NonceBlockhashNotExpired) + } else if n == Self::NonceUnexpectedBlockhashValue as i64 { + Some(Self::NonceUnexpectedBlockhashValue) + } else { + None + } + } + #[inline] + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} + +impl ToPrimitive for SystemError { + #[inline] + fn to_i64(&self) -> Option { + Some(match *self { + Self::AccountAlreadyInUse => Self::AccountAlreadyInUse as i64, + Self::ResultWithNegativeLamports => Self::ResultWithNegativeLamports as i64, + Self::InvalidProgramId => Self::InvalidProgramId as i64, + Self::InvalidAccountDataLength => Self::InvalidAccountDataLength as i64, + Self::MaxSeedLengthExceeded => Self::MaxSeedLengthExceeded as i64, + Self::AddressWithSeedMismatch => Self::AddressWithSeedMismatch as i64, + Self::NonceNoRecentBlockhashes => Self::NonceNoRecentBlockhashes as i64, + Self::NonceBlockhashNotExpired => Self::NonceBlockhashNotExpired as i64, + Self::NonceUnexpectedBlockhashValue => Self::NonceUnexpectedBlockhashValue as i64, + }) + } + #[inline] + fn to_u64(&self) -> Option { + self.to_i64().map(|x| x as u64) + } +} + +impl core::error::Error for SystemError {} + +impl ToStr for SystemError { + fn to_str(&self) -> &'static str { + match self { + SystemError::AccountAlreadyInUse => "an account with the same address already exists", + SystemError::ResultWithNegativeLamports => { + "account does not have enough SOL to perform the operation" + } + SystemError::InvalidProgramId => "cannot assign account to this program id", + SystemError::InvalidAccountDataLength => "cannot allocate account data of this length", + SystemError::MaxSeedLengthExceeded => "length of requested seed is too long", + SystemError::AddressWithSeedMismatch => { + "provided address does not match addressed derived from seed" + } + SystemError::NonceNoRecentBlockhashes => { + "advancing stored nonce requires a populated RecentBlockhashes sysvar" + } + SystemError::NonceBlockhashNotExpired => "stored nonce is still in recent_blockhashes", + SystemError::NonceUnexpectedBlockhashValue => { + "specified nonce does not match stored nonce" + } + } + } +} + +impl core::fmt::Display for SystemError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.write_str(self.to_str()) + } +} + +impl From for ProgramError { + fn from(e: SystemError) -> Self { + Self::Custom(e as u32) + } +} + +impl TryFrom for SystemError { + type Error = ProgramError; + fn try_from(error: u32) -> Result { + match error { + 0 => Ok(SystemError::AccountAlreadyInUse), + 1 => Ok(SystemError::ResultWithNegativeLamports), + 2 => Ok(SystemError::InvalidProgramId), + 3 => Ok(SystemError::InvalidAccountDataLength), + 4 => Ok(SystemError::MaxSeedLengthExceeded), + 5 => Ok(SystemError::AddressWithSeedMismatch), + 6 => Ok(SystemError::NonceNoRecentBlockhashes), + 7 => Ok(SystemError::NonceBlockhashNotExpired), + 8 => Ok(SystemError::NonceUnexpectedBlockhashValue), + _ => Err(ProgramError::InvalidArgument), + } + } +} + +impl From for SystemError { + fn from(error: u64) -> Self { + SystemError::from_u64(error).unwrap() + } +} + +#[cfg(test)] +mod tests { + use {super::SystemError, num_traits::FromPrimitive, strum::IntoEnumIterator}; + + #[test] + fn test_system_error_from_primitive_exhaustive() { + for variant in SystemError::iter() { + let variant_i64 = variant.clone() as i64; + assert_eq!( + SystemError::from_repr(variant_i64 as usize), + SystemError::from_i64(variant_i64) + ); + assert_eq!(SystemError::from(variant_i64 as u64), variant); + } + } +} diff --git a/system-interface/src/instruction.rs b/system-interface/src/instruction.rs new file mode 100644 index 000000000..d6d9f2241 --- /dev/null +++ b/system-interface/src/instruction.rs @@ -0,0 +1,1718 @@ +//! Instructions and constructors for the system program. +//! +//! The system program is responsible for the creation of accounts and [nonce +//! accounts][na]. It is responsible for transferring lamports from accounts +//! owned by the system program, including typical user wallet accounts. +//! +//! [na]: https://docs.solanalabs.com/implemented-proposals/durable-tx-nonces +//! +//! Account creation typically involves three steps: [`allocate`] space, +//! [`transfer`] lamports for rent, [`assign`] to its owning program. The +//! [`create_account`] function does all three at once. All new accounts must +//! contain enough lamports to be [rent exempt], or else the creation +//! instruction will fail. +//! +//! [rent exempt]: https://solana.com/docs/core/accounts#rent-exemption +//! +//! The accounts created by the System program can either be user-controlled, +//! where the secret keys are held outside the blockchain, +//! or they can be [program derived addresses][pda], +//! where write access to accounts is granted by an owning program. +//! +//! [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address +//! +//! Most of the functions in this module construct an [`Instruction`], that must +//! be submitted to the runtime for execution, either via RPC, typically with +//! [`RpcClient`], or through [cross-program invocation][cpi]. +//! +//! When invoking through CPI, the [`invoke`] or [`invoke_signed`] instruction +//! requires all account references to be provided explicitly as [`AccountInfo`] +//! values. The account references required are specified in the documentation +//! for the [`SystemInstruction`] variants for each System program instruction, +//! and these variants are linked from the documentation for their constructors. +//! +//! [`RpcClient`]: https://docs.rs/solana-client/latest/solana_client/rpc_client/struct.RpcClient.html +//! [cpi]: https://docs.rs/solana-cpi/latest/solana_cpi/index.html +//! [`invoke`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +//! [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html +//! [`AccountInfo`]: https://docs.rs/solana-account-info/latest/solana_account_info/struct.AccountInfo.html +//! [`Instruction`]: +//! https://docs.rs/solana-instruction/latest/solana_instruction/struct.Instruction.html + +use solana_pubkey::Pubkey; +#[cfg(feature = "bincode")] +use { + crate::program::ID, + solana_instruction::{AccountMeta, Instruction}, +}; + +// Inline some constants to avoid dependencies. +// +// Note: replace these inline IDs with the corresponding value from +// `solana_sdk_ids` once the version is updated to 2.2.0. + +#[cfg(feature = "bincode")] +const RECENT_BLOCKHASHES_ID: Pubkey = + Pubkey::from_str_const("SysvarRecentB1ockHashes11111111111111111111"); + +#[cfg(feature = "bincode")] +const RENT_ID: Pubkey = Pubkey::from_str_const("SysvarRent111111111111111111111111111111111"); + +#[cfg(feature = "bincode")] +#[cfg(test)] +static_assertions::const_assert_eq!(solana_nonce::state::State::size(), NONCE_STATE_SIZE); +/// The serialized size of the nonce state. +#[cfg(feature = "bincode")] +const NONCE_STATE_SIZE: usize = 80; + +/// An instruction to the system program. +#[cfg_attr( + feature = "frozen-abi", + solana_frozen_abi_macro::frozen_abi(digest = "8M189WgLE19cw1iYDAFLNJKoAUKyqF9jsKYennJi5BfK"), + derive( + solana_frozen_abi_macro::AbiExample, + solana_frozen_abi_macro::AbiEnumVisitor + ) +)] +#[cfg_attr( + feature = "serde", + derive(serde_derive::Deserialize, serde_derive::Serialize) +)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum SystemInstruction { + /// Create a new account + /// + /// # Account references + /// 0. `[WRITE, SIGNER]` Funding account + /// 1. `[WRITE, SIGNER]` New account + CreateAccount { + /// Number of lamports to transfer to the new account + lamports: u64, + + /// Number of bytes of memory to allocate + space: u64, + + /// Address of program that will own the new account + owner: Pubkey, + }, + + /// Assign account to a program + /// + /// # Account references + /// 0. `[WRITE, SIGNER]` Assigned account public key + Assign { + /// Owner program account + owner: Pubkey, + }, + + /// Transfer lamports + /// + /// # Account references + /// 0. `[WRITE, SIGNER]` Funding account + /// 1. `[WRITE]` Recipient account + Transfer { lamports: u64 }, + + /// Create a new account at an address derived from a base pubkey and a seed + /// + /// # Account references + /// 0. `[WRITE, SIGNER]` Funding account + /// 1. `[WRITE]` Created account + /// 2. `[SIGNER]` (optional) Base account; the account matching the base Pubkey below must be + /// provided as a signer, but may be the same as the funding account + /// and provided as account 0 + CreateAccountWithSeed { + /// Base public key + base: Pubkey, + + /// String of ASCII chars, no longer than `Pubkey::MAX_SEED_LEN` + seed: String, + + /// Number of lamports to transfer to the new account + lamports: u64, + + /// Number of bytes of memory to allocate + space: u64, + + /// Owner program account address + owner: Pubkey, + }, + + /// Consumes a stored nonce, replacing it with a successor + /// + /// # Account references + /// 0. `[WRITE]` Nonce account + /// 1. `[]` RecentBlockhashes sysvar + /// 2. `[SIGNER]` Nonce authority + AdvanceNonceAccount, + + /// Withdraw funds from a nonce account + /// + /// # Account references + /// 0. `[WRITE]` Nonce account + /// 1. `[WRITE]` Recipient account + /// 2. `[]` RecentBlockhashes sysvar + /// 3. `[]` Rent sysvar + /// 4. `[SIGNER]` Nonce authority + /// + /// The `u64` parameter is the lamports to withdraw, which must leave the + /// account balance above the rent exempt reserve or at zero. + WithdrawNonceAccount(u64), + + /// Drive state of Uninitialized nonce account to Initialized, setting the nonce value + /// + /// # Account references + /// 0. `[WRITE]` Nonce account + /// 1. `[]` RecentBlockhashes sysvar + /// 2. `[]` Rent sysvar + /// + /// The `Pubkey` parameter specifies the entity authorized to execute nonce + /// instruction on the account + /// + /// No signatures are required to execute this instruction, enabling derived + /// nonce account addresses + InitializeNonceAccount(Pubkey), + + /// Change the entity authorized to execute nonce instructions on the account + /// + /// # Account references + /// 0. `[WRITE]` Nonce account + /// 1. `[SIGNER]` Nonce authority + /// + /// The `Pubkey` parameter identifies the entity to authorize + AuthorizeNonceAccount(Pubkey), + + /// Allocate space in a (possibly new) account without funding + /// + /// # Account references + /// 0. `[WRITE, SIGNER]` New account + Allocate { + /// Number of bytes of memory to allocate + space: u64, + }, + + /// Allocate space for and assign an account at an address + /// derived from a base public key and a seed + /// + /// # Account references + /// 0. `[WRITE]` Allocated account + /// 1. `[SIGNER]` Base account + AllocateWithSeed { + /// Base public key + base: Pubkey, + + /// String of ASCII chars, no longer than `pubkey::MAX_SEED_LEN` + seed: String, + + /// Number of bytes of memory to allocate + space: u64, + + /// Owner program account + owner: Pubkey, + }, + + /// Assign account to a program based on a seed + /// + /// # Account references + /// 0. `[WRITE]` Assigned account + /// 1. `[SIGNER]` Base account + AssignWithSeed { + /// Base public key + base: Pubkey, + + /// String of ASCII chars, no longer than `pubkey::MAX_SEED_LEN` + seed: String, + + /// Owner program account + owner: Pubkey, + }, + + /// Transfer lamports from a derived address + /// + /// # Account references + /// 0. `[WRITE]` Funding account + /// 1. `[SIGNER]` Base for funding account + /// 2. `[WRITE]` Recipient account + TransferWithSeed { + /// Amount to transfer + lamports: u64, + + /// Seed to use to derive the funding account address + from_seed: String, + + /// Owner to use to derive the funding account address + from_owner: Pubkey, + }, + + /// One-time idempotent upgrade of legacy nonce versions in order to bump + /// them out of chain blockhash domain. + /// + /// # Account references + /// 0. `[WRITE]` Nonce account + UpgradeNonceAccount, +} + +/// Create an account. +/// +/// This function produces an [`Instruction`] which must be submitted in a +/// [`Transaction`] or [invoked] to take effect, containing a serialized +/// [`SystemInstruction::CreateAccount`]. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// Account creation typically involves three steps: [`allocate`] space, +/// [`transfer`] lamports for rent, [`assign`] to its owning program. The +/// [`create_account`] function does all three at once. +/// +/// # Required signers +/// +/// The `from_pubkey` and `to_pubkey` signers must sign the transaction. +/// +/// # Examples +/// +/// These examples use a single invocation of +/// [`SystemInstruction::CreateAccount`] to create a new account, allocate some +/// space, transfer it the minimum lamports for rent exemption, and assign it to +/// the system program, +/// +/// ## Example: client-side RPC +/// +/// This example submits the instruction from an RPC client. +/// The `payer` and `new_account` are signers. +/// +/// ``` +/// # use solana_example_mocks::{solana_sdk, solana_rpc_client}; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_sdk::{ +/// signature::{Keypair, Signer}, +/// transaction::Transaction, +/// }; +/// use solana_system_interface::{instruction, program}; +/// use anyhow::Result; +/// +/// fn create_account( +/// client: &RpcClient, +/// payer: &Keypair, +/// new_account: &Keypair, +/// space: u64, +/// ) -> Result<()> { +/// let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?; +/// let instr = instruction::create_account( +/// &payer.pubkey(), +/// &new_account.pubkey(), +/// rent, +/// space, +/// &program::ID, +/// ); +/// +/// let blockhash = client.get_latest_blockhash()?; +/// let tx = Transaction::new_signed_with_payer( +/// &[instr], +/// Some(&payer.pubkey()), +/// &[payer, new_account], +/// blockhash, +/// ); +/// +/// let _sig = client.send_and_confirm_transaction(&tx)?; +/// +/// Ok(()) +/// } +/// # let payer = Keypair::new(); +/// # let new_account = Keypair::new(); +/// # let client = RpcClient::new(String::new()); +/// # create_account(&client, &payer, &new_account, 0); +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +/// +/// ## Example: on-chain program +/// +/// This example submits the instruction from an on-chain Solana program. The +/// created account is a [program derived address][pda]. The `payer` and +/// `new_account_pda` are signers, with `new_account_pda` being signed for +/// virtually by the program itself via [`invoke_signed`], `payer` being signed +/// for by the client that submitted the transaction. +/// +/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address +/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html +/// +/// ``` +/// use borsh::{BorshDeserialize, BorshSerialize}; +/// use solana_account_info::{next_account_info, AccountInfo}; +/// use solana_cpi::invoke_signed; +/// use solana_program_entrypoint::entrypoint; +/// use solana_program_error::ProgramResult; +/// use solana_pubkey::Pubkey; +/// use solana_system_interface::{instruction, program}; +/// use solana_sysvar::{rent::Rent, Sysvar}; +/// +/// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// pub struct CreateAccountInstruction { +/// /// The PDA seed used to distinguish the new account from other PDAs +/// pub new_account_seed: [u8; 16], +/// /// The PDA bump seed +/// pub new_account_bump_seed: u8, +/// /// The amount of space to allocate for `new_account_pda` +/// pub space: u64, +/// } +/// +/// entrypoint!(process_instruction); +/// +/// fn process_instruction( +/// program_id: &Pubkey, +/// accounts: &[AccountInfo], +/// instruction_data: &[u8], +/// ) -> ProgramResult { +/// let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?; +/// +/// let account_info_iter = &mut accounts.iter(); +/// +/// let payer = next_account_info(account_info_iter)?; +/// let new_account_pda = next_account_info(account_info_iter)?; +/// let system_account = next_account_info(account_info_iter)?; +/// +/// assert!(payer.is_signer); +/// assert!(payer.is_writable); +/// // Note that `new_account_pda` is not a signer yet. +/// // This program will sign for it via `invoke_signed`. +/// assert!(!new_account_pda.is_signer); +/// assert!(new_account_pda.is_writable); +/// assert!(program::check_id(system_account.key)); +/// +/// let new_account_seed = &instr.new_account_seed; +/// let new_account_bump_seed = instr.new_account_bump_seed; +/// +/// let rent = Rent::get()? +/// .minimum_balance(instr.space.try_into().expect("overflow")); +/// +/// invoke_signed( +/// &instruction::create_account( +/// payer.key, +/// new_account_pda.key, +/// rent, +/// instr.space, +/// &program::ID +/// ), +/// &[payer.clone(), new_account_pda.clone()], +/// &[&[ +/// payer.key.as_ref(), +/// new_account_seed, +/// &[new_account_bump_seed], +/// ]], +/// )?; +/// +/// Ok(()) +/// } +/// ``` +#[cfg(feature = "bincode")] +pub fn create_account( + from_pubkey: &Pubkey, + to_pubkey: &Pubkey, + lamports: u64, + space: u64, + owner: &Pubkey, +) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*from_pubkey, true), + AccountMeta::new(*to_pubkey, true), + ]; + Instruction::new_with_bincode( + ID, + &SystemInstruction::CreateAccount { + lamports, + space, + owner: *owner, + }, + account_metas, + ) +} + +// we accept `to` as a parameter so that callers do their own error handling when +// calling create_with_seed() +#[cfg(feature = "bincode")] +pub fn create_account_with_seed( + from_pubkey: &Pubkey, + to_pubkey: &Pubkey, // must match create_with_seed(base, seed, owner) + base: &Pubkey, + seed: &str, + lamports: u64, + space: u64, + owner: &Pubkey, +) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*from_pubkey, true), + AccountMeta::new(*to_pubkey, false), + AccountMeta::new_readonly(*base, true), + ]; + + Instruction::new_with_bincode( + ID, + &SystemInstruction::CreateAccountWithSeed { + base: *base, + seed: seed.to_string(), + lamports, + space, + owner: *owner, + }, + account_metas, + ) +} + +/// Assign ownership of an account from the system program. +/// +/// This function produces an [`Instruction`] which must be submitted in a +/// [`Transaction`] or [invoked] to take effect, containing a serialized +/// [`SystemInstruction::Assign`]. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// # Required signers +/// +/// The `pubkey` signer must sign the transaction. +/// +/// # Examples +/// +/// These examples allocate space for an account, transfer it the minimum +/// balance for rent exemption, and assign the account to a program. +/// +/// ## Example: client-side RPC +/// +/// This example submits the instructions from an RPC client. +/// It assigns the account to a provided program account. +/// The `payer` and `new_account` are signers. +/// +/// ``` +/// # use solana_example_mocks::{solana_sdk, solana_rpc_client}; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_pubkey::Pubkey; +/// use solana_sdk::{ +/// signature::{Keypair, Signer}, +/// transaction::Transaction, +/// }; +/// use solana_system_interface::instruction; +/// use anyhow::Result; +/// +/// fn create_account( +/// client: &RpcClient, +/// payer: &Keypair, +/// new_account: &Keypair, +/// owning_program: &Pubkey, +/// space: u64, +/// ) -> Result<()> { +/// let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?; +/// +/// let transfer_instr = instruction::transfer( +/// &payer.pubkey(), +/// &new_account.pubkey(), +/// rent, +/// ); +/// +/// let allocate_instr = instruction::allocate( +/// &new_account.pubkey(), +/// space, +/// ); +/// +/// let assign_instr = instruction::assign( +/// &new_account.pubkey(), +/// owning_program, +/// ); +/// +/// let blockhash = client.get_latest_blockhash()?; +/// let tx = Transaction::new_signed_with_payer( +/// &[transfer_instr, allocate_instr, assign_instr], +/// Some(&payer.pubkey()), +/// &[payer, new_account], +/// blockhash, +/// ); +/// +/// let _sig = client.send_and_confirm_transaction(&tx)?; +/// +/// Ok(()) +/// } +/// # let client = RpcClient::new(String::new()); +/// # let payer = Keypair::new(); +/// # let new_account = Keypair::new(); +/// # let owning_program = Pubkey::new_unique(); +/// # create_account(&client, &payer, &new_account, &owning_program, 1); +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +/// +/// ## Example: on-chain program +/// +/// This example submits the instructions from an on-chain Solana program. The +/// created account is a [program derived address][pda], funded by `payer`, and +/// assigned to the running program. The `payer` and `new_account_pda` are +/// signers, with `new_account_pda` being signed for virtually by the program +/// itself via [`invoke_signed`], `payer` being signed for by the client that +/// submitted the transaction. +/// +/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address +/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html +/// +/// ``` +/// use borsh::{BorshDeserialize, BorshSerialize}; +/// use solana_account_info::{next_account_info, AccountInfo}; +/// use solana_cpi::invoke_signed; +/// use solana_program_entrypoint::entrypoint; +/// use solana_program_error::ProgramResult; +/// use solana_pubkey::Pubkey; +/// use solana_system_interface::{instruction, program}; +/// use solana_sysvar::{rent::Rent, Sysvar}; +/// +/// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// pub struct CreateAccountInstruction { +/// /// The PDA seed used to distinguish the new account from other PDAs +/// pub new_account_seed: [u8; 16], +/// /// The PDA bump seed +/// pub new_account_bump_seed: u8, +/// /// The amount of space to allocate for `new_account_pda` +/// pub space: u64, +/// } +/// +/// entrypoint!(process_instruction); +/// +/// fn process_instruction( +/// program_id: &Pubkey, +/// accounts: &[AccountInfo], +/// instruction_data: &[u8], +/// ) -> ProgramResult { +/// let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?; +/// +/// let account_info_iter = &mut accounts.iter(); +/// +/// let payer = next_account_info(account_info_iter)?; +/// let new_account_pda = next_account_info(account_info_iter)?; +/// let system_account = next_account_info(account_info_iter)?; +/// +/// assert!(payer.is_signer); +/// assert!(payer.is_writable); +/// // Note that `new_account_pda` is not a signer yet. +/// // This program will sign for it via `invoke_signed`. +/// assert!(!new_account_pda.is_signer); +/// assert!(new_account_pda.is_writable); +/// assert!(program::check_id(system_account.key)); +/// +/// let new_account_seed = &instr.new_account_seed; +/// let new_account_bump_seed = instr.new_account_bump_seed; +/// +/// let rent = Rent::get()? +/// .minimum_balance(instr.space.try_into().expect("overflow")); +/// +/// invoke_signed( +/// &instruction::create_account( +/// payer.key, +/// new_account_pda.key, +/// rent, +/// instr.space, +/// &program::ID +/// ), +/// &[payer.clone(), new_account_pda.clone()], +/// &[&[ +/// payer.key.as_ref(), +/// new_account_seed, +/// &[new_account_bump_seed], +/// ]], +/// )?; +/// +/// Ok(()) +/// } +/// ``` +#[cfg(feature = "bincode")] +pub fn assign(pubkey: &Pubkey, owner: &Pubkey) -> Instruction { + let account_metas = vec![AccountMeta::new(*pubkey, true)]; + Instruction::new_with_bincode( + ID, + &SystemInstruction::Assign { owner: *owner }, + account_metas, + ) +} + +#[cfg(feature = "bincode")] +pub fn assign_with_seed( + address: &Pubkey, // must match create_with_seed(base, seed, owner) + base: &Pubkey, + seed: &str, + owner: &Pubkey, +) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*address, false), + AccountMeta::new_readonly(*base, true), + ]; + Instruction::new_with_bincode( + ID, + &SystemInstruction::AssignWithSeed { + base: *base, + seed: seed.to_string(), + owner: *owner, + }, + account_metas, + ) +} + +/// Transfer lamports from an account owned by the system program. +/// +/// This function produces an [`Instruction`] which must be submitted in a +/// [`Transaction`] or [invoked] to take effect, containing a serialized +/// [`SystemInstruction::Transfer`]. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// # Required signers +/// +/// The `from_pubkey` signer must sign the transaction. +/// +/// # Examples +/// +/// These examples allocate space for an account, transfer it the minimum +/// balance for rent exemption, and assign the account to a program. +/// +/// # Example: client-side RPC +/// +/// This example submits the instructions from an RPC client. +/// It assigns the account to a provided program account. +/// The `payer` and `new_account` are signers. +/// +/// ``` +/// # use solana_example_mocks::{solana_sdk, solana_rpc_client}; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_pubkey::Pubkey; +/// use solana_sdk::{ +/// signature::{Keypair, Signer}, +/// transaction::Transaction, +/// }; +/// use solana_system_interface::instruction; +/// use anyhow::Result; +/// +/// fn create_account( +/// client: &RpcClient, +/// payer: &Keypair, +/// new_account: &Keypair, +/// owning_program: &Pubkey, +/// space: u64, +/// ) -> Result<()> { +/// let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?; +/// +/// let transfer_instr = instruction::transfer( +/// &payer.pubkey(), +/// &new_account.pubkey(), +/// rent, +/// ); +/// +/// let allocate_instr = instruction::allocate( +/// &new_account.pubkey(), +/// space, +/// ); +/// +/// let assign_instr = instruction::assign( +/// &new_account.pubkey(), +/// owning_program, +/// ); +/// +/// let blockhash = client.get_latest_blockhash()?; +/// let tx = Transaction::new_signed_with_payer( +/// &[transfer_instr, allocate_instr, assign_instr], +/// Some(&payer.pubkey()), +/// &[payer, new_account], +/// blockhash, +/// ); +/// +/// let _sig = client.send_and_confirm_transaction(&tx)?; +/// +/// Ok(()) +/// } +/// # let client = RpcClient::new(String::new()); +/// # let payer = Keypair::new(); +/// # let new_account = Keypair::new(); +/// # let owning_program = Pubkey::new_unique(); +/// # create_account(&client, &payer, &new_account, &owning_program, 1); +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +/// +/// ## Example: on-chain program +/// +/// This example submits the instructions from an on-chain Solana program. The +/// created account is a [program derived address][pda], funded by `payer`, and +/// assigned to the running program. The `payer` and `new_account_pda` are +/// signers, with `new_account_pda` being signed for virtually by the program +/// itself via [`invoke_signed`], `payer` being signed for by the client that +/// submitted the transaction. +/// +/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address +/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html +/// +/// ``` +/// # use borsh::{BorshDeserialize, BorshSerialize}; +/// use solana_account_info::{next_account_info, AccountInfo}; +/// use solana_cpi::invoke_signed; +/// use solana_program_entrypoint::entrypoint; +/// use solana_program_error::ProgramResult; +/// use solana_pubkey::Pubkey; +/// use solana_system_interface::{instruction, program}; +/// use solana_sysvar::{rent::Rent, Sysvar}; +/// +/// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] +/// pub struct CreateAccountInstruction { +/// /// The PDA seed used to distinguish the new account from other PDAs +/// pub new_account_seed: [u8; 16], +/// /// The PDA bump seed +/// pub new_account_bump_seed: u8, +/// /// The amount of space to allocate for `new_account_pda` +/// pub space: u64, +/// } +/// +/// entrypoint!(process_instruction); +/// +/// fn process_instruction( +/// program_id: &Pubkey, +/// accounts: &[AccountInfo], +/// instruction_data: &[u8], +/// ) -> ProgramResult { +/// let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?; +/// +/// let account_info_iter = &mut accounts.iter(); +/// +/// let payer = next_account_info(account_info_iter)?; +/// let new_account_pda = next_account_info(account_info_iter)?; +/// let system_account = next_account_info(account_info_iter)?; +/// +/// assert!(payer.is_signer); +/// assert!(payer.is_writable); +/// // Note that `new_account_pda` is not a signer yet. +/// // This program will sign for it via `invoke_signed`. +/// assert!(!new_account_pda.is_signer); +/// assert!(new_account_pda.is_writable); +/// assert!(program::check_id(system_account.key)); +/// +/// let new_account_seed = &instr.new_account_seed; +/// let new_account_bump_seed = instr.new_account_bump_seed; +/// +/// let rent = Rent::get()? +/// .minimum_balance(instr.space.try_into().expect("overflow")); +/// +/// invoke_signed( +/// &instruction::create_account( +/// payer.key, +/// new_account_pda.key, +/// rent, +/// instr.space, +/// &program::ID +/// ), +/// &[payer.clone(), new_account_pda.clone()], +/// &[&[ +/// payer.key.as_ref(), +/// new_account_seed, +/// &[new_account_bump_seed], +/// ]], +/// )?; +/// +/// Ok(()) +/// } +/// ``` +#[cfg(feature = "bincode")] +pub fn transfer(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*from_pubkey, true), + AccountMeta::new(*to_pubkey, false), + ]; + Instruction::new_with_bincode(ID, &SystemInstruction::Transfer { lamports }, account_metas) +} + +#[cfg(feature = "bincode")] +pub fn transfer_with_seed( + from_pubkey: &Pubkey, // must match create_with_seed(base, seed, owner) + from_base: &Pubkey, + from_seed: String, + from_owner: &Pubkey, + to_pubkey: &Pubkey, + lamports: u64, +) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*from_pubkey, false), + AccountMeta::new_readonly(*from_base, true), + AccountMeta::new(*to_pubkey, false), + ]; + Instruction::new_with_bincode( + ID, + &SystemInstruction::TransferWithSeed { + lamports, + from_seed, + from_owner: *from_owner, + }, + account_metas, + ) +} + +/// Allocate space for an account. +/// +/// This function produces an [`Instruction`] which must be submitted in a +/// [`Transaction`] or [invoked] to take effect, containing a serialized +/// [`SystemInstruction::Allocate`]. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// The transaction will fail if the account already has size greater than 0, +/// or if the requested size is greater than [`super::MAX_PERMITTED_DATA_LENGTH`]. +/// +/// # Required signers +/// +/// The `pubkey` signer must sign the transaction. +/// +/// # Examples +/// +/// These examples allocate space for an account, transfer it the minimum +/// balance for rent exemption, and assign the account to a program. +/// +/// # Example: client-side RPC +/// +/// This example submits the instructions from an RPC client. +/// It assigns the account to a provided program account. +/// The `payer` and `new_account` are signers. +/// +/// ``` +/// # use solana_example_mocks::{solana_sdk, solana_rpc_client}; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_pubkey::Pubkey; +/// use solana_sdk::{ +/// signature::{Keypair, Signer}, +/// transaction::Transaction, +/// }; +/// use solana_system_interface::instruction; +/// use anyhow::Result; +/// +/// fn create_account( +/// client: &RpcClient, +/// payer: &Keypair, +/// new_account: &Keypair, +/// owning_program: &Pubkey, +/// space: u64, +/// ) -> Result<()> { +/// let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?; +/// +/// let transfer_instr = instruction::transfer( +/// &payer.pubkey(), +/// &new_account.pubkey(), +/// rent, +/// ); +/// +/// let allocate_instr = instruction::allocate( +/// &new_account.pubkey(), +/// space, +/// ); +/// +/// let assign_instr = instruction::assign( +/// &new_account.pubkey(), +/// owning_program, +/// ); +/// +/// let blockhash = client.get_latest_blockhash()?; +/// let tx = Transaction::new_signed_with_payer( +/// &[transfer_instr, allocate_instr, assign_instr], +/// Some(&payer.pubkey()), +/// &[payer, new_account], +/// blockhash, +/// ); +/// +/// let _sig = client.send_and_confirm_transaction(&tx)?; +/// +/// Ok(()) +/// } +/// # let client = RpcClient::new(String::new()); +/// # let payer = Keypair::new(); +/// # let new_account = Keypair::new(); +/// # let owning_program = Pubkey::new_unique(); +/// # create_account(&client, &payer, &new_account, &owning_program, 1); +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +/// +/// ## Example: on-chain program +/// +/// This example submits the instructions from an on-chain Solana program. The +/// created account is a [program derived address][pda], funded by `payer`, and +/// assigned to the running program. The `payer` and `new_account_pda` are +/// signers, with `new_account_pda` being signed for virtually by the program +/// itself via [`invoke_signed`], `payer` being signed for by the client that +/// submitted the transaction. +/// +/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address +/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html +/// +/// ``` +/// use borsh::{BorshDeserialize, BorshSerialize}; +/// use solana_account_info::{next_account_info, AccountInfo}; +/// use solana_cpi::invoke_signed; +/// use solana_program_entrypoint::entrypoint; +/// use solana_program_error::ProgramResult; +/// use solana_pubkey::Pubkey; +/// use solana_system_interface::{instruction, program}; +/// use solana_sysvar::{rent::Rent, Sysvar}; +/// +/// #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// pub struct CreateAccountInstruction { +/// /// The PDA seed used to distinguish the new account from other PDAs +/// pub new_account_seed: [u8; 16], +/// /// The PDA bump seed +/// pub new_account_bump_seed: u8, +/// /// The amount of space to allocate for `new_account_pda` +/// pub space: u64, +/// } +/// +/// entrypoint!(process_instruction); +/// +/// fn process_instruction( +/// program_id: &Pubkey, +/// accounts: &[AccountInfo], +/// instruction_data: &[u8], +/// ) -> ProgramResult { +/// let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?; +/// +/// let account_info_iter = &mut accounts.iter(); +/// +/// let payer = next_account_info(account_info_iter)?; +/// let new_account_pda = next_account_info(account_info_iter)?; +/// let system_account = next_account_info(account_info_iter)?; +/// +/// assert!(payer.is_signer); +/// assert!(payer.is_writable); +/// // Note that `new_account_pda` is not a signer yet. +/// // This program will sign for it via `invoke_signed`. +/// assert!(!new_account_pda.is_signer); +/// assert!(new_account_pda.is_writable); +/// assert!(program::check_id(system_account.key)); +/// +/// let new_account_seed = &instr.new_account_seed; +/// let new_account_bump_seed = instr.new_account_bump_seed; +/// +/// let rent = Rent::get()? +/// .minimum_balance(instr.space.try_into().expect("overflow")); +/// +/// invoke_signed( +/// &instruction::create_account( +/// payer.key, +/// new_account_pda.key, +/// rent, +/// instr.space, +/// &program::ID +/// ), +/// &[payer.clone(), new_account_pda.clone()], +/// &[&[ +/// payer.key.as_ref(), +/// new_account_seed, +/// &[new_account_bump_seed], +/// ]], +/// )?; +/// +/// Ok(()) +/// } +/// ``` +#[cfg(feature = "bincode")] +pub fn allocate(pubkey: &Pubkey, space: u64) -> Instruction { + let account_metas = vec![AccountMeta::new(*pubkey, true)]; + Instruction::new_with_bincode(ID, &SystemInstruction::Allocate { space }, account_metas) +} + +#[cfg(feature = "bincode")] +pub fn allocate_with_seed( + address: &Pubkey, // must match create_with_seed(base, seed, owner) + base: &Pubkey, + seed: &str, + space: u64, + owner: &Pubkey, +) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*address, false), + AccountMeta::new_readonly(*base, true), + ]; + Instruction::new_with_bincode( + ID, + &SystemInstruction::AllocateWithSeed { + base: *base, + seed: seed.to_string(), + space, + owner: *owner, + }, + account_metas, + ) +} + +/// Transfer lamports from an account owned by the system program to multiple accounts. +/// +/// This function produces a vector of [`Instruction`]s which must be submitted +/// in a [`Transaction`] or [invoked] to take effect, containing serialized +/// [`SystemInstruction::Transfer`]s. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// # Required signers +/// +/// The `from_pubkey` signer must sign the transaction. +/// +/// # Examples +/// +/// ## Example: client-side RPC +/// +/// This example performs multiple transfers in a single transaction. +/// +/// ``` +/// # use solana_example_mocks::{solana_sdk, solana_rpc_client}; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_pubkey::Pubkey; +/// use solana_sdk::{ +/// signature::{Keypair, Signer}, +/// transaction::Transaction, +/// }; +/// use solana_system_interface::instruction; +/// use anyhow::Result; +/// +/// fn transfer_lamports_to_many( +/// client: &RpcClient, +/// from: &Keypair, +/// to_and_amount: &[(Pubkey, u64)], +/// ) -> Result<()> { +/// let instrs = instruction::transfer_many(&from.pubkey(), to_and_amount); +/// +/// let blockhash = client.get_latest_blockhash()?; +/// let tx = Transaction::new_signed_with_payer( +/// &instrs, +/// Some(&from.pubkey()), +/// &[from], +/// blockhash, +/// ); +/// +/// let _sig = client.send_and_confirm_transaction(&tx)?; +/// +/// Ok(()) +/// } +/// # let from = Keypair::new(); +/// # let to_and_amount = vec![ +/// # (Pubkey::new_unique(), 1_000), +/// # (Pubkey::new_unique(), 2_000), +/// # (Pubkey::new_unique(), 3_000), +/// # ]; +/// # let client = RpcClient::new(String::new()); +/// # transfer_lamports_to_many(&client, &from, &to_and_amount); +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +/// +/// ## Example: on-chain program +/// +/// This example makes multiple transfers out of a "bank" account, +/// a [program derived address][pda] owned by the calling program. +/// This example submits the instructions from an on-chain Solana program. The +/// created account is a [program derived address][pda], and it is assigned to +/// the running program. The `payer` and `new_account_pda` are signers, with +/// `new_account_pda` being signed for virtually by the program itself via +/// [`invoke_signed`], `payer` being signed for by the client that submitted the +/// transaction. +/// +/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address +/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html +/// +/// ``` +/// # use borsh::{BorshDeserialize, BorshSerialize}; +/// use solana_account_info::{next_account_info, next_account_infos, AccountInfo}; +/// use solana_cpi::invoke_signed; +/// use solana_program_entrypoint::entrypoint; +/// use solana_program_error::ProgramResult; +/// use solana_pubkey::Pubkey; +/// use solana_system_interface::{instruction, program}; +/// +/// /// # Accounts +/// /// +/// /// - 0: bank_pda - writable +/// /// - 1: system_program - executable +/// /// - *: to - writable +/// # #[derive(BorshSerialize, BorshDeserialize, Debug)] +/// # #[borsh(crate = "borsh")] +/// pub struct TransferLamportsToManyInstruction { +/// pub bank_pda_bump_seed: u8, +/// pub amount_list: Vec, +/// } +/// +/// entrypoint!(process_instruction); +/// +/// fn process_instruction( +/// program_id: &Pubkey, +/// accounts: &[AccountInfo], +/// instruction_data: &[u8], +/// ) -> ProgramResult { +/// let instr = TransferLamportsToManyInstruction::deserialize(&mut &instruction_data[..])?; +/// +/// let account_info_iter = &mut accounts.iter(); +/// +/// let bank_pda = next_account_info(account_info_iter)?; +/// let bank_pda_bump_seed = instr.bank_pda_bump_seed; +/// let system_account = next_account_info(account_info_iter)?; +/// +/// assert!(program::check_id(system_account.key)); +/// +/// let to_accounts = next_account_infos(account_info_iter, account_info_iter.len())?; +/// +/// for to_account in to_accounts { +/// assert!(to_account.is_writable); +/// // ... do other verification ... +/// } +/// +/// let to_and_amount = to_accounts +/// .iter() +/// .zip(instr.amount_list.iter()) +/// .map(|(to, amount)| (*to.key, *amount)) +/// .collect::>(); +/// +/// let instrs = instruction::transfer_many(bank_pda.key, to_and_amount.as_ref()); +/// +/// for instr in instrs { +/// invoke_signed(&instr, accounts, &[&[b"bank", &[bank_pda_bump_seed]]])?; +/// } +/// +/// Ok(()) +/// } +/// ``` +#[cfg(feature = "bincode")] +pub fn transfer_many(from_pubkey: &Pubkey, to_lamports: &[(Pubkey, u64)]) -> Vec { + to_lamports + .iter() + .map(|(to_pubkey, lamports)| transfer(from_pubkey, to_pubkey, *lamports)) + .collect() +} + +#[cfg(feature = "bincode")] +pub fn create_nonce_account_with_seed( + from_pubkey: &Pubkey, + nonce_pubkey: &Pubkey, + base: &Pubkey, + seed: &str, + authority: &Pubkey, + lamports: u64, +) -> Vec { + vec![ + create_account_with_seed( + from_pubkey, + nonce_pubkey, + base, + seed, + lamports, + NONCE_STATE_SIZE as u64, + &ID, + ), + Instruction::new_with_bincode( + ID, + &SystemInstruction::InitializeNonceAccount(*authority), + vec![ + AccountMeta::new(*nonce_pubkey, false), + #[allow(deprecated)] + AccountMeta::new_readonly(RECENT_BLOCKHASHES_ID, false), + AccountMeta::new_readonly(RENT_ID, false), + ], + ), + ] +} + +/// Create an account containing a durable transaction nonce. +/// +/// This function produces a vector of [`Instruction`]s which must be submitted +/// in a [`Transaction`] or [invoked] to take effect, containing a serialized +/// [`SystemInstruction::CreateAccount`] and +/// [`SystemInstruction::InitializeNonceAccount`]. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// A [durable transaction nonce][dtn] is a special account that enables +/// execution of transactions that have been signed in the past. +/// +/// Standard Solana transactions include a [recent blockhash][rbh] (sometimes +/// referred to as a _[nonce]_). During execution the Solana runtime verifies +/// the recent blockhash is approximately less than two minutes old, and that in +/// those two minutes no other identical transaction with the same blockhash has +/// been executed. These checks prevent accidental replay of transactions. +/// Consequently, it is not possible to sign a transaction, wait more than two +/// minutes, then successfully execute that transaction. +/// +/// [dtn]: https://docs.solanalabs.com/implemented-proposals/durable-tx-nonces +/// [rbh]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#structfield.recent_blockhash +/// [nonce]: https://en.wikipedia.org/wiki/Cryptographic_nonce +/// +/// Durable transaction nonces are an alternative to the standard recent +/// blockhash nonce. They are stored in accounts on chain, and every time they +/// are used their value is changed to a new value for their next use. The +/// runtime verifies that each durable nonce value is only used once, and there +/// are no restrictions on how "old" the nonce is. Because they are stored on +/// chain and require additional instructions to use, transacting with durable +/// transaction nonces is more expensive than with standard transactions. +/// +/// The value of the durable nonce is itself a blockhash and is accessible via +/// the [`blockhash`] field of [`nonce::state::Data`], which is deserialized +/// from the nonce account data. +/// +/// [`blockhash`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#structfield.recent_blockhash +/// [`nonce::state::Data`]: https://docs.rs/solana-nonce/latest/solana_nonce/state/struct.Data.html +/// +/// The basic durable transaction nonce lifecycle is +/// +/// 1) Create the nonce account with the `create_nonce_account` instruction. +/// 2) Submit specially-formed transactions that include the +/// [`advance_nonce_account`] instruction. +/// 3) Destroy the nonce account by withdrawing its lamports with the +/// [`withdraw_nonce_account`] instruction. +/// +/// Nonce accounts have an associated _authority_ account, which is stored in +/// their account data, and can be changed with the [`authorize_nonce_account`] +/// instruction. The authority must sign transactions that include the +/// `advance_nonce_account`, `authorize_nonce_account` and +/// `withdraw_nonce_account` instructions. +/// +/// Nonce accounts are owned by the system program. +/// +/// This constructor creates a [`SystemInstruction::CreateAccount`] instruction +/// and a [`SystemInstruction::InitializeNonceAccount`] instruction. +/// +/// # Required signers +/// +/// The `from_pubkey` and `nonce_pubkey` signers must sign the transaction. +/// +/// # Examples +/// +/// Create a nonce account from an off-chain client: +/// +/// ``` +/// # use solana_example_mocks::solana_keypair; +/// # use solana_example_mocks::solana_signer; +/// # use solana_example_mocks::solana_rpc_client; +/// # use solana_example_mocks::solana_transaction; +/// use solana_keypair::Keypair; +/// use solana_nonce::state::State; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_signer::Signer; +/// use solana_system_interface::instruction; +/// use solana_transaction::Transaction; +/// use anyhow::Result; +/// +/// fn submit_create_nonce_account_tx( +/// client: &RpcClient, +/// payer: &Keypair, +/// ) -> Result<()> { +/// +/// let nonce_account = Keypair::new(); +/// +/// let nonce_rent = client.get_minimum_balance_for_rent_exemption(State::size())?; +/// let instr = instruction::create_nonce_account( +/// &payer.pubkey(), +/// &nonce_account.pubkey(), +/// &payer.pubkey(), // Make the fee payer the nonce account authority +/// nonce_rent, +/// ); +/// +/// let mut tx = Transaction::new_with_payer(&instr, Some(&payer.pubkey())); +/// +/// let blockhash = client.get_latest_blockhash()?; +/// tx.try_sign(&[&nonce_account, payer], blockhash)?; +/// +/// client.send_and_confirm_transaction(&tx)?; +/// +/// Ok(()) +/// } +/// # +/// # let client = RpcClient::new(String::new()); +/// # let payer = Keypair::new(); +/// # submit_create_nonce_account_tx(&client, &payer)?; +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +#[cfg(feature = "bincode")] +pub fn create_nonce_account( + from_pubkey: &Pubkey, + nonce_pubkey: &Pubkey, + authority: &Pubkey, + lamports: u64, +) -> Vec { + vec![ + create_account( + from_pubkey, + nonce_pubkey, + lamports, + NONCE_STATE_SIZE as u64, + &ID, + ), + Instruction::new_with_bincode( + ID, + &SystemInstruction::InitializeNonceAccount(*authority), + vec![ + AccountMeta::new(*nonce_pubkey, false), + #[allow(deprecated)] + AccountMeta::new_readonly(RECENT_BLOCKHASHES_ID, false), + AccountMeta::new_readonly(RENT_ID, false), + ], + ), + ] +} + +/// Advance the value of a durable transaction nonce. +/// +/// This function produces an [`Instruction`] which must be submitted in a +/// [`Transaction`] or [invoked] to take effect, containing a serialized +/// [`SystemInstruction::AdvanceNonceAccount`]. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// Every transaction that relies on a durable transaction nonce must contain a +/// [`SystemInstruction::AdvanceNonceAccount`] instruction as the first +/// instruction in the [`Message`], as created by this function. When included +/// in the first position, the Solana runtime recognizes the transaction as one +/// that relies on a durable transaction nonce and processes it accordingly. The +/// [`Message::new_with_nonce`] function can be used to construct a `Message` in +/// the correct format without calling `advance_nonce_account` directly. +/// +/// When constructing a transaction that includes an `AdvanceNonceInstruction` +/// the [`recent_blockhash`] must be treated differently — instead of +/// setting it to a recent blockhash, the value of the nonce must be retrieved +/// and deserialized from the nonce account, and that value specified as the +/// "recent blockhash". A nonce account can be deserialized with the +/// [`solana_rpc_client_nonce_utils::data_from_account`][dfa] function. +/// +/// For further description of durable transaction nonces see +/// [`create_nonce_account`]. +/// +/// [`Message`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html +/// [`Message::new_with_nonce`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#method.new_with_nonce +/// [`recent_blockhash`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#structfield.recent_blockhash +/// [dfa]: https://docs.rs/solana-rpc-client-nonce-utils/latest/solana_rpc_client_nonce_utils/fn.data_from_account.html +/// +/// # Required signers +/// +/// The `authorized_pubkey` signer must sign the transaction. +/// +/// # Examples +/// +/// Create and sign a transaction with a durable nonce: +/// +/// ``` +/// # use solana_example_mocks::solana_sdk; +/// # use solana_example_mocks::solana_rpc_client; +/// # use solana_example_mocks::solana_rpc_client_nonce_utils; +/// # use solana_sdk::account::Account; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_pubkey::Pubkey; +/// use solana_sdk::{ +/// message::Message, +/// signature::{Keypair, Signer}, +/// transaction::Transaction, +/// }; +/// use solana_system_interface::instruction; +/// use std::path::Path; +/// use anyhow::Result; +/// +/// fn create_transfer_tx_with_nonce( +/// client: &RpcClient, +/// nonce_account_pubkey: &Pubkey, +/// payer: &Keypair, +/// receiver: &Pubkey, +/// amount: u64, +/// tx_path: &Path, +/// ) -> Result<()> { +/// +/// let instr_transfer = instruction::transfer( +/// &payer.pubkey(), +/// receiver, +/// amount, +/// ); +/// +/// // In this example, `payer` is `nonce_account_pubkey`'s authority +/// let instr_advance_nonce_account = instruction::advance_nonce_account( +/// nonce_account_pubkey, +/// &payer.pubkey(), +/// ); +/// +/// // The `advance_nonce_account` instruction must be the first issued in +/// // the transaction. +/// let message = Message::new( +/// &[ +/// instr_advance_nonce_account, +/// instr_transfer +/// ], +/// Some(&payer.pubkey()), +/// ); +/// +/// let mut tx = Transaction::new_unsigned(message); +/// +/// // Sign the tx with nonce_account's `blockhash` instead of the +/// // network's latest blockhash. +/// # client.set_get_account_response(*nonce_account_pubkey, Account { +/// # lamports: 1, +/// # data: vec![0], +/// # owner: solana_sdk::system_program::ID, +/// # executable: false, +/// # }); +/// let nonce_account = client.get_account(nonce_account_pubkey)?; +/// let nonce_data = solana_rpc_client_nonce_utils::data_from_account(&nonce_account)?; +/// let blockhash = nonce_data.blockhash(); +/// +/// tx.try_sign(&[payer], blockhash)?; +/// +/// // Save the signed transaction locally for later submission. +/// save_tx_to_file(&tx_path, &tx)?; +/// +/// Ok(()) +/// } +/// # +/// # fn save_tx_to_file(path: &Path, tx: &Transaction) -> Result<()> { +/// # Ok(()) +/// # } +/// # +/// # let client = RpcClient::new(String::new()); +/// # let nonce_account_pubkey = Pubkey::new_unique(); +/// # let payer = Keypair::new(); +/// # let receiver = Pubkey::new_unique(); +/// # create_transfer_tx_with_nonce(&client, &nonce_account_pubkey, &payer, &receiver, 1024, Path::new("new_tx"))?; +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +#[cfg(feature = "bincode")] +pub fn advance_nonce_account(nonce_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*nonce_pubkey, false), + #[allow(deprecated)] + AccountMeta::new_readonly(RECENT_BLOCKHASHES_ID, false), + AccountMeta::new_readonly(*authorized_pubkey, true), + ]; + Instruction::new_with_bincode(ID, &SystemInstruction::AdvanceNonceAccount, account_metas) +} + +/// Withdraw lamports from a durable transaction nonce account. +/// +/// This function produces an [`Instruction`] which must be submitted in a +/// [`Transaction`] or [invoked] to take effect, containing a serialized +/// [`SystemInstruction::WithdrawNonceAccount`]. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// Withdrawing the entire balance of a nonce account will cause the runtime to +/// destroy it upon successful completion of the transaction. +/// +/// Otherwise, nonce accounts must maintain a balance greater than or equal to +/// the minimum required for [rent exemption]. If the result of this instruction +/// would leave the nonce account with a balance less than required for rent +/// exemption, but also greater than zero, then the transaction will fail. +/// +/// [rent exemption]: https://solana.com/docs/core/accounts#rent-exemption +/// +/// This constructor creates a [`SystemInstruction::WithdrawNonceAccount`] +/// instruction. +/// +/// # Required signers +/// +/// The `authorized_pubkey` signer must sign the transaction. +/// +/// # Examples +/// +/// ``` +/// # use solana_example_mocks::solana_sdk; +/// # use solana_example_mocks::solana_rpc_client; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_pubkey::Pubkey; +/// use solana_sdk::{ +/// signature::{Keypair, Signer}, +/// transaction::Transaction, +/// }; +/// use solana_system_interface::instruction; +/// use anyhow::Result; +/// +/// fn submit_withdraw_nonce_account_tx( +/// client: &RpcClient, +/// nonce_account_pubkey: &Pubkey, +/// authorized_account: &Keypair, +/// ) -> Result<()> { +/// +/// let nonce_balance = client.get_balance(nonce_account_pubkey)?; +/// +/// let instr = instruction::withdraw_nonce_account( +/// nonce_account_pubkey, +/// &authorized_account.pubkey(), +/// &authorized_account.pubkey(), +/// nonce_balance, +/// ); +/// +/// let mut tx = Transaction::new_with_payer(&[instr], Some(&authorized_account.pubkey())); +/// +/// let blockhash = client.get_latest_blockhash()?; +/// tx.try_sign(&[authorized_account], blockhash)?; +/// +/// client.send_and_confirm_transaction(&tx)?; +/// +/// Ok(()) +/// } +/// # +/// # let client = RpcClient::new(String::new()); +/// # let nonce_account_pubkey = Pubkey::new_unique(); +/// # let payer = Keypair::new(); +/// # submit_withdraw_nonce_account_tx(&client, &nonce_account_pubkey, &payer)?; +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +#[cfg(feature = "bincode")] +pub fn withdraw_nonce_account( + nonce_pubkey: &Pubkey, + authorized_pubkey: &Pubkey, + to_pubkey: &Pubkey, + lamports: u64, +) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*nonce_pubkey, false), + AccountMeta::new(*to_pubkey, false), + #[allow(deprecated)] + AccountMeta::new_readonly(RECENT_BLOCKHASHES_ID, false), + AccountMeta::new_readonly(RENT_ID, false), + AccountMeta::new_readonly(*authorized_pubkey, true), + ]; + Instruction::new_with_bincode( + ID, + &SystemInstruction::WithdrawNonceAccount(lamports), + account_metas, + ) +} + +/// Change the authority of a durable transaction nonce account. +/// +/// This function produces an [`Instruction`] which must be submitted in a +/// [`Transaction`] or [invoked] to take effect, containing a serialized +/// [`SystemInstruction::AuthorizeNonceAccount`]. +/// +/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html +/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html +/// +/// This constructor creates a [`SystemInstruction::AuthorizeNonceAccount`] +/// instruction. +/// +/// # Required signers +/// +/// The `authorized_pubkey` signer must sign the transaction. +/// +/// # Examples +/// +/// ``` +/// # use solana_example_mocks::solana_sdk; +/// # use solana_example_mocks::solana_rpc_client; +/// use solana_rpc_client::rpc_client::RpcClient; +/// use solana_pubkey::Pubkey; +/// use solana_sdk::{ +/// signature::{Keypair, Signer}, +/// transaction::Transaction, +/// }; +/// use solana_system_interface::instruction; +/// use anyhow::Result; +/// +/// fn authorize_nonce_account_tx( +/// client: &RpcClient, +/// nonce_account_pubkey: &Pubkey, +/// authorized_account: &Keypair, +/// new_authority_pubkey: &Pubkey, +/// ) -> Result<()> { +/// +/// let instr = instruction::authorize_nonce_account( +/// nonce_account_pubkey, +/// &authorized_account.pubkey(), +/// new_authority_pubkey, +/// ); +/// +/// let mut tx = Transaction::new_with_payer(&[instr], Some(&authorized_account.pubkey())); +/// +/// let blockhash = client.get_latest_blockhash()?; +/// tx.try_sign(&[authorized_account], blockhash)?; +/// +/// client.send_and_confirm_transaction(&tx)?; +/// +/// Ok(()) +/// } +/// # +/// # let client = RpcClient::new(String::new()); +/// # let nonce_account_pubkey = Pubkey::new_unique(); +/// # let payer = Keypair::new(); +/// # let new_authority_pubkey = Pubkey::new_unique(); +/// # authorize_nonce_account_tx(&client, &nonce_account_pubkey, &payer, &new_authority_pubkey)?; +/// # +/// # Ok::<(), anyhow::Error>(()) +/// ``` +#[cfg(feature = "bincode")] +pub fn authorize_nonce_account( + nonce_pubkey: &Pubkey, + authorized_pubkey: &Pubkey, + new_authority: &Pubkey, +) -> Instruction { + let account_metas = vec![ + AccountMeta::new(*nonce_pubkey, false), + AccountMeta::new_readonly(*authorized_pubkey, true), + ]; + Instruction::new_with_bincode( + ID, + &SystemInstruction::AuthorizeNonceAccount(*new_authority), + account_metas, + ) +} + +/// One-time idempotent upgrade of legacy nonce versions in order to bump +/// them out of chain blockhash domain. +#[cfg(feature = "bincode")] +pub fn upgrade_nonce_account(nonce_pubkey: Pubkey) -> Instruction { + let account_metas = vec![AccountMeta::new(nonce_pubkey, /*is_signer:*/ false)]; + Instruction::new_with_bincode(ID, &SystemInstruction::UpgradeNonceAccount, account_metas) +} + +#[cfg(feature = "bincode")] +#[cfg(test)] +mod tests { + use {super::*, solana_sysvar_id::SysvarId}; + + fn get_keys(instruction: &Instruction) -> Vec { + instruction.accounts.iter().map(|x| x.pubkey).collect() + } + + #[allow(deprecated)] + #[test] + fn test_constants() { + // Ensure that the constants are in sync with the solana program. + assert_eq!( + RECENT_BLOCKHASHES_ID, + solana_sysvar::recent_blockhashes::RecentBlockhashes::id(), + ); + + // Ensure that the constants are in sync with the solana rent. + assert_eq!(RENT_ID, solana_sysvar::rent::Rent::id()); + } + + #[test] + fn test_move_many() { + let alice_pubkey = Pubkey::new_unique(); + let bob_pubkey = Pubkey::new_unique(); + let carol_pubkey = Pubkey::new_unique(); + let to_lamports = vec![(bob_pubkey, 1), (carol_pubkey, 2)]; + + let instructions = transfer_many(&alice_pubkey, &to_lamports); + assert_eq!(instructions.len(), 2); + assert_eq!(get_keys(&instructions[0]), vec![alice_pubkey, bob_pubkey]); + assert_eq!(get_keys(&instructions[1]), vec![alice_pubkey, carol_pubkey]); + } + + #[test] + fn test_create_nonce_account() { + let from_pubkey = Pubkey::new_unique(); + let nonce_pubkey = Pubkey::new_unique(); + let authorized = nonce_pubkey; + let ixs = create_nonce_account(&from_pubkey, &nonce_pubkey, &authorized, 42); + assert_eq!(ixs.len(), 2); + let ix = &ixs[0]; + assert_eq!(ix.program_id, crate::program::ID); + let pubkeys: Vec<_> = ix.accounts.iter().map(|am| am.pubkey).collect(); + assert!(pubkeys.contains(&from_pubkey)); + assert!(pubkeys.contains(&nonce_pubkey)); + } +} diff --git a/system-interface/src/lib.rs b/system-interface/src/lib.rs new file mode 100644 index 000000000..e0514cd55 --- /dev/null +++ b/system-interface/src/lib.rs @@ -0,0 +1,29 @@ +//! The System program interface. + +#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +pub mod error; +pub mod instruction; + +#[cfg(test)] +static_assertions::const_assert!(MAX_PERMITTED_DATA_LENGTH <= u32::MAX as u64); +/// Maximum permitted size of account data (10 MiB). +/// +// SBF program entrypoint assumes that the max account data length +// will fit inside a u32. If this constant no longer fits in a u32, +// the entrypoint deserialization code in the SDK must be updated. +pub const MAX_PERMITTED_DATA_LENGTH: u64 = 10 * 1024 * 1024; + +#[cfg(test)] +static_assertions::const_assert_eq!(MAX_PERMITTED_DATA_LENGTH, 10_485_760); +/// Maximum permitted size of new allocations per transaction, in bytes. +/// +/// The value was chosen such that at least one max sized account could be created, +/// plus some additional resize allocations. +pub const MAX_PERMITTED_ACCOUNTS_DATA_ALLOCATIONS_PER_TRANSACTION: i64 = + MAX_PERMITTED_DATA_LENGTH as i64 * 2; + +pub mod program { + solana_pubkey::declare_id!("11111111111111111111111111111111"); +} diff --git a/sysvar/Cargo.toml b/sysvar/Cargo.toml index 0a277c13c..1086bc5ea 100644 --- a/sysvar/Cargo.toml +++ b/sysvar/Cargo.toml @@ -15,14 +15,10 @@ all-features = true rustdoc-args = ["--cfg=docsrs"] [features] -bincode = ["dep:bincode", "serde", "solana-stake-interface/bincode"] +bincode = ["dep:bincode", "serde"] bytemuck = ["dep:bytemuck", "dep:bytemuck_derive"] -dev-context-only-utils = ["bincode", "bytemuck", "solana-instructions-sysvar/dev-context-only-utils"] -frozen-abi = [ - "dep:solana-frozen-abi", - "dep:solana-frozen-abi-macro", - "solana-stake-interface/frozen-abi", -] +dev-context-only-utils = ["bincode", "bytemuck"] +frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"] serde = [ "dep:serde", "dep:serde_derive", @@ -34,7 +30,6 @@ serde = [ "solana-rent/serde", "solana-slot-hashes/serde", "solana-slot-history/serde", - "solana-stake-interface/serde", ] [dependencies] @@ -52,23 +47,20 @@ solana-fee-calculator = { workspace = true } solana-frozen-abi = { workspace = true, optional = true } solana-frozen-abi-macro = { workspace = true, optional = true } solana-hash = { workspace = true, features = ["bytemuck"] } -solana-instruction = { workspace = true } -solana-instructions-sysvar = { workspace = true } solana-last-restart-slot = { workspace = true, features = ["sysvar"] } solana-program-entrypoint = { workspace = true } solana-program-error = { workspace = true } solana-pubkey = { workspace = true } solana-rent = { workspace = true, features = ["sysvar"] } -solana-sanitize = { workspace = true } solana-sdk-ids = { workspace = true } solana-sdk-macro = { workspace = true } solana-slot-hashes = { workspace = true, features = ["sysvar"] } solana-slot-history = { workspace = true, features = ["sysvar"] } -solana-stake-interface = { workspace = true } solana-sysvar-id = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] base64 = { workspace = true } +solana-instruction = { workspace = true, features = ["std"] } solana-program-memory = { workspace = true } [target.'cfg(target_os = "solana")'.dependencies] @@ -77,9 +69,8 @@ solana-define-syscall = { workspace = true } [dev-dependencies] anyhow = { workspace = true } serial_test = { workspace = true } +solana-example-mocks = { path = "../example-mocks" } solana-msg = { workspace = true } -solana-program = { path = "../program" } -solana-sdk = { path = "../sdk" } solana-sha256-hasher = { workspace = true } solana-sysvar = { path = ".", features = ["dev-context-only-utils"] } test-case = { workspace = true } diff --git a/sysvar/src/clock.rs b/sysvar/src/clock.rs index f81fa5684..bde88bab2 100644 --- a/sysvar/src/clock.rs +++ b/sysvar/src/clock.rs @@ -39,7 +39,7 @@ //! # let p = Clock::id(); //! # let l = &mut 1169280; //! # let d = &mut vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0]; -//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0); +//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false); //! # let accounts = &[a.clone(), a]; //! # process_instruction( //! # &Pubkey::new_unique(), @@ -57,7 +57,7 @@ //! # use solana_msg::msg; //! # use solana_program_error::{ProgramError, ProgramResult}; //! # use solana_pubkey::Pubkey; -//! # use solana_sysvar::Sysvar; +//! # use solana_sysvar::{Sysvar, SysvarSerialize}; //! # use solana_sdk_ids::sysvar::clock; //! # //! fn process_instruction( @@ -80,7 +80,7 @@ //! # let p = Clock::id(); //! # let l = &mut 1169280; //! # let d = &mut vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0]; -//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0); +//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false); //! # let accounts = &[a.clone(), a]; //! # process_instruction( //! # &Pubkey::new_unique(), @@ -94,10 +94,10 @@ //! //! ``` //! # use solana_clock::Clock; -//! # use solana_program::example_mocks::solana_sdk; -//! # use solana_program::example_mocks::solana_rpc_client; +//! # use solana_example_mocks::solana_account; +//! # use solana_example_mocks::solana_rpc_client; //! # use solana_rpc_client::rpc_client::RpcClient; -//! # use solana_sdk::account::Account; +//! # use solana_account::Account; //! # use solana_sdk_ids::sysvar::clock; //! # use anyhow::Result; //! # @@ -107,7 +107,6 @@ //! # data: vec![240, 153, 233, 7, 0, 0, 0, 0, 11, 115, 118, 98, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 0, 0, 121, 50, 119, 98, 0, 0, 0, 0], //! # owner: solana_sdk_ids::system_program::ID, //! # executable: false, -//! # rent_epoch: 307, //! # }); //! # //! let clock = client.get_account(&clock::ID)?; @@ -123,13 +122,16 @@ //! ``` #[cfg(feature = "bincode")] +use crate::SysvarSerialize; use crate::{impl_sysvar_get, Sysvar}; pub use { solana_clock::Clock, solana_sdk_ids::sysvar::clock::{check_id, id, ID}, }; -#[cfg(feature = "bincode")] impl Sysvar for Clock { impl_sysvar_get!(sol_get_clock_sysvar); } + +#[cfg(feature = "bincode")] +impl SysvarSerialize for Clock {} diff --git a/sysvar/src/epoch_rewards.rs b/sysvar/src/epoch_rewards.rs index 160bb0446..ae741e4ef 100755 --- a/sysvar/src/epoch_rewards.rs +++ b/sysvar/src/epoch_rewards.rs @@ -57,7 +57,7 @@ //! # ..EpochRewards::default() //! # }; //! # let mut d: Vec = bincode::serialize(&epoch_rewards).unwrap(); -//! # let a = AccountInfo::new(&p, false, false, l, &mut d, &p, false, 0); +//! # let a = AccountInfo::new(&p, false, false, l, &mut d, &p, false); //! # let accounts = &[a.clone(), a]; //! # process_instruction( //! # &Pubkey::new_unique(), @@ -75,7 +75,7 @@ //! # use solana_msg::msg; //! # use solana_program_error::{ProgramError, ProgramResult}; //! # use solana_pubkey::Pubkey; -//! # use solana_sysvar::Sysvar; +//! # use solana_sysvar::{Sysvar, SysvarSerialize}; //! # use solana_sdk_ids::sysvar::epoch_rewards; //! # //! fn process_instruction( @@ -105,7 +105,7 @@ //! # ..EpochRewards::default() //! # }; //! # let mut d: Vec = bincode::serialize(&epoch_rewards).unwrap(); -//! # let a = AccountInfo::new(&p, false, false, l, &mut d, &p, false, 0); +//! # let a = AccountInfo::new(&p, false, false, l, &mut d, &p, false); //! # let accounts = &[a.clone(), a]; //! # process_instruction( //! # &Pubkey::new_unique(), @@ -119,10 +119,10 @@ //! //! ``` //! # use solana_epoch_rewards::EpochRewards; -//! # use solana_program::example_mocks::solana_sdk; -//! # use solana_program::example_mocks::solana_rpc_client; +//! # use solana_example_mocks::solana_account; +//! # use solana_example_mocks::solana_rpc_client; //! # use solana_rpc_client::rpc_client::RpcClient; -//! # use solana_sdk::account::Account; +//! # use solana_account::Account; //! # use solana_sdk_ids::sysvar::epoch_rewards; //! # use anyhow::Result; //! # @@ -140,7 +140,6 @@ //! # data, //! # owner: solana_sdk_ids::system_program::ID, //! # executable: false, -//! # rent_epoch: 307, //! # }); //! # //! let epoch_rewards = client.get_account(&epoch_rewards::ID)?; @@ -156,13 +155,16 @@ //! ``` #[cfg(feature = "bincode")] +use crate::SysvarSerialize; use crate::{impl_sysvar_get, Sysvar}; pub use { solana_epoch_rewards::EpochRewards, solana_sdk_ids::sysvar::epoch_rewards::{check_id, id, ID}, }; -#[cfg(feature = "bincode")] impl Sysvar for EpochRewards { impl_sysvar_get!(sol_get_epoch_rewards_sysvar); } + +#[cfg(feature = "bincode")] +impl SysvarSerialize for EpochRewards {} diff --git a/sysvar/src/epoch_schedule.rs b/sysvar/src/epoch_schedule.rs index ac9bdb72f..d189434a3 100644 --- a/sysvar/src/epoch_schedule.rs +++ b/sysvar/src/epoch_schedule.rs @@ -39,7 +39,7 @@ //! # let p = EpochSchedule::id(); //! # let l = &mut 1120560; //! # let d = &mut vec![0, 32, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0); +//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false); //! # let accounts = &[a.clone(), a]; //! # process_instruction( //! # &Pubkey::new_unique(), @@ -58,7 +58,7 @@ //! # use solana_program_error::{ProgramError, ProgramResult}; //! # use solana_pubkey::Pubkey; //! # use solana_sdk_ids::sysvar::epoch_schedule; -//! # use solana_sysvar::Sysvar; +//! # use solana_sysvar::{Sysvar, SysvarSerialize}; //! fn process_instruction( //! program_id: &Pubkey, //! accounts: &[AccountInfo], @@ -79,7 +79,7 @@ //! # let p = EpochSchedule::id(); //! # let l = &mut 1120560; //! # let d = &mut vec![0, 32, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0); +//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false); //! # let accounts = &[a.clone(), a]; //! # process_instruction( //! # &Pubkey::new_unique(), @@ -93,10 +93,10 @@ //! //! ``` //! # use solana_epoch_schedule::EpochSchedule; -//! # use solana_program::example_mocks::solana_sdk; -//! # use solana_program::example_mocks::solana_rpc_client; +//! # use solana_example_mocks::solana_account; +//! # use solana_example_mocks::solana_rpc_client; //! # use solana_rpc_client::rpc_client::RpcClient; -//! # use solana_sdk::account::Account; +//! # use solana_account::Account; //! # use solana_sdk_ids::sysvar::epoch_schedule; //! # use anyhow::Result; //! # @@ -106,7 +106,6 @@ //! # data: vec![0, 32, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //! # owner: solana_sdk_ids::system_program::ID, //! # executable: false, -//! # rent_epoch: 307, //! # }); //! # //! let epoch_schedule = client.get_account(&epoch_schedule::ID)?; @@ -121,13 +120,16 @@ //! # Ok::<(), anyhow::Error>(()) //! ``` #[cfg(feature = "bincode")] +use crate::SysvarSerialize; use crate::{impl_sysvar_get, Sysvar}; pub use { solana_epoch_schedule::EpochSchedule, solana_sdk_ids::sysvar::epoch_schedule::{check_id, id, ID}, }; -#[cfg(feature = "bincode")] impl Sysvar for EpochSchedule { impl_sysvar_get!(sol_get_epoch_schedule_sysvar); } + +#[cfg(feature = "bincode")] +impl SysvarSerialize for EpochSchedule {} diff --git a/sysvar/src/fees.rs b/sysvar/src/fees.rs index 820f744e2..cf40e48ed 100644 --- a/sysvar/src/fees.rs +++ b/sysvar/src/fees.rs @@ -21,12 +21,14 @@ #![allow(deprecated)] #[cfg(feature = "bincode")] -use crate::{impl_sysvar_get, Sysvar}; +use crate::SysvarSerialize; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; pub use solana_sdk_ids::sysvar::fees::{check_id, id, ID}; use { - solana_fee_calculator::FeeCalculator, solana_sdk_macro::CloneZeroed, + crate::{impl_sysvar_get, Sysvar}, + solana_fee_calculator::FeeCalculator, + solana_sdk_macro::CloneZeroed, solana_sysvar_id::impl_deprecated_sysvar_id, }; @@ -53,11 +55,13 @@ impl Fees { } } -#[cfg(feature = "bincode")] impl Sysvar for Fees { impl_sysvar_get!(sol_get_fees_sysvar); } +#[cfg(feature = "bincode")] +impl SysvarSerialize for Fees {} + #[cfg(test)] mod tests { use super::*; diff --git a/sysvar/src/last_restart_slot.rs b/sysvar/src/last_restart_slot.rs index f6e462ca8..5ee10b621 100644 --- a/sysvar/src/last_restart_slot.rs +++ b/sysvar/src/last_restart_slot.rs @@ -37,13 +37,16 @@ //! ``` //! #[cfg(feature = "bincode")] +use crate::SysvarSerialize; use crate::{impl_sysvar_get, Sysvar}; pub use { solana_last_restart_slot::LastRestartSlot, solana_sdk_ids::sysvar::last_restart_slot::{check_id, id, ID}, }; -#[cfg(feature = "bincode")] impl Sysvar for LastRestartSlot { impl_sysvar_get!(sol_get_last_restart_slot); } + +#[cfg(feature = "bincode")] +impl SysvarSerialize for LastRestartSlot {} diff --git a/sysvar/src/lib.rs b/sysvar/src/lib.rs index 10ee892a6..8f54ba252 100644 --- a/sysvar/src/lib.rs +++ b/sysvar/src/lib.rs @@ -5,8 +5,8 @@ //! Sysvars are special accounts that contain dynamically-updated data about the //! network cluster, the blockchain history, and the executing transaction. Each //! sysvar is defined in its own submodule within this module. The [`clock`], -//! [`epoch_schedule`], [`instructions`], and [`rent`] sysvars are most useful -//! to on-chain programs. +//! [`epoch_schedule`], and [`rent`] sysvars are most useful to on-chain +//! programs. //! //! Simple sysvars implement the [`Sysvar::get`] method, which loads a sysvar //! directly from the runtime, as in this example that logs the `clock` sysvar: @@ -31,13 +31,13 @@ //! //! Since Solana sysvars are accounts, if the `AccountInfo` is provided to the //! program, then the program can deserialize the sysvar with -//! [`Sysvar::from_account_info`] to access its data, as in this example that +//! [`SysvarSerialize::from_account_info`] to access its data, as in this example that //! again logs the [`clock`] sysvar. //! //! ``` //! use solana_account_info::{AccountInfo, next_account_info}; //! use solana_msg::msg; -//! use solana_sysvar::Sysvar; +//! use solana_sysvar::{Sysvar, SysvarSerialize}; //! use solana_program_error::ProgramResult; //! use solana_pubkey::Pubkey; //! @@ -83,19 +83,9 @@ pub mod __private { pub use solana_define_syscall::definitions; pub use {solana_program_entrypoint::SUCCESS, solana_program_error::ProgramError}; } -use solana_pubkey::Pubkey; -#[allow(deprecated)] -#[doc(inline)] -#[deprecated( - since = "2.0.0", - note = "please use `solana_sdk::reserved_account_keys::ReservedAccountKeys` instead" -)] -pub use sysvar_ids::ALL_IDS; #[cfg(feature = "bincode")] -use { - solana_account_info::AccountInfo, solana_program_error::ProgramError, - solana_sysvar_id::SysvarId, -}; +use {solana_account_info::AccountInfo, solana_sysvar_id::SysvarId}; +use {solana_program_error::ProgramError, solana_pubkey::Pubkey}; pub mod clock; pub mod epoch_rewards; @@ -108,47 +98,37 @@ pub mod rent; pub mod rewards; pub mod slot_hashes; pub mod slot_history; -pub mod stake_history; -#[deprecated( - since = "2.0.0", - note = "please use `solana_sdk::reserved_account_keys::ReservedAccountKeys` instead" -)] -mod sysvar_ids { - use {super::*, lazy_static::lazy_static}; - lazy_static! { - // This will be deprecated and so this list shouldn't be modified - pub static ref ALL_IDS: Vec = vec![ - clock::id(), - epoch_schedule::id(), - #[allow(deprecated)] - fees::id(), - #[allow(deprecated)] - recent_blockhashes::id(), - rent::id(), - rewards::id(), - slot_hashes::id(), - slot_history::id(), - stake_history::id(), - solana_sdk_ids::sysvar::instructions::id(), - ]; - } -} +/// Return value indicating that the `offset + length` is greater than the length of +/// the sysvar data. +// +// Defined in the bpf loader as [`OFFSET_LENGTH_EXCEEDS_SYSVAR`](https://github.com/anza-xyz/agave/blob/master/programs/bpf_loader/src/syscalls/sysvar.rs#L172). +const OFFSET_LENGTH_EXCEEDS_SYSVAR: u64 = 1; + +/// Return value indicating that the sysvar was not found. +// +// Defined in the bpf loader as [`SYSVAR_NOT_FOUND`](https://github.com/anza-xyz/agave/blob/master/programs/bpf_loader/src/syscalls/sysvar.rs#L171). +const SYSVAR_NOT_FOUND: u64 = 2; -/// Returns `true` of the given `Pubkey` is a sysvar account. -#[deprecated( - since = "2.0.0", - note = "please check the account's owner or use solana_sdk::reserved_account_keys::ReservedAccountKeys instead" -)] -#[allow(deprecated)] -pub fn is_sysvar_id(id: &Pubkey) -> bool { - ALL_IDS.iter().any(|key| key == id) +/// Interface for loading a sysvar. +pub trait Sysvar: Default + Sized { + /// Load the sysvar directly from the runtime. + /// + /// This is the preferred way to load a sysvar. Calling this method does not + /// incur any deserialization overhead, and does not require the sysvar + /// account to be passed to the program. + /// + /// Not all sysvars support this method. If not, it returns + /// [`ProgramError::UnsupportedSysvar`]. + fn get() -> Result { + Err(ProgramError::UnsupportedSysvar) + } } #[cfg(feature = "bincode")] /// A type that holds sysvar data. -pub trait Sysvar: - SysvarId + Default + Sized + serde::Serialize + serde::de::DeserializeOwned +pub trait SysvarSerialize: + Sysvar + SysvarId + serde::Serialize + serde::de::DeserializeOwned { /// The size in bytes of the sysvar as serialized account data. fn size_of() -> usize { @@ -176,18 +156,6 @@ pub trait Sysvar: fn to_account_info(&self, account_info: &mut AccountInfo) -> Option<()> { bincode::serialize_into(&mut account_info.data.borrow_mut()[..], self).ok() } - - /// Load the sysvar directly from the runtime. - /// - /// This is the preferred way to load a sysvar. Calling this method does not - /// incur any deserialization overhead, and does not require the sysvar - /// account to be passed to the program. - /// - /// Not all sysvars support this method. If not, it returns - /// [`ProgramError::UnsupportedSysvar`]. - fn get() -> Result { - Err(ProgramError::UnsupportedSysvar) - } } /// Implements the [`Sysvar::get`] method for both SBF and host targets. @@ -206,7 +174,8 @@ macro_rules! impl_sysvar_get { match result { $crate::__private::SUCCESS => Ok(var), - e => Err(e.into()), + // Unexpected errors are folded into `UnsupportedSysvar`. + _ => Err($crate::__private::ProgramError::UnsupportedSysvar), } } }; @@ -214,7 +183,7 @@ macro_rules! impl_sysvar_get { /// Handler for retrieving a slice of sysvar data from the `sol_get_sysvar` /// syscall. -fn get_sysvar( +pub fn get_sysvar( dst: &mut [u8], sysvar_id: &Pubkey, offset: u64, @@ -239,7 +208,10 @@ fn get_sysvar( match result { solana_program_entrypoint::SUCCESS => Ok(()), - e => Err(e.into()), + OFFSET_LENGTH_EXCEEDS_SYSVAR => Err(solana_program_error::ProgramError::InvalidArgument), + SYSVAR_NOT_FOUND => Err(solana_program_error::ProgramError::UnsupportedSysvar), + // Unexpected errors are folded into `UnsupportedSysvar`. + _ => Err(solana_program_error::ProgramError::UnsupportedSysvar), } } @@ -249,7 +221,6 @@ mod tests { super::*, crate::program_stubs::{set_syscall_stubs, SyscallStubs}, serde_derive::{Deserialize, Serialize}, - solana_clock::Epoch, solana_program_entrypoint::SUCCESS, solana_program_error::ProgramError, solana_pubkey::Pubkey, @@ -272,6 +243,7 @@ mod tests { } } impl Sysvar for TestSysvar {} + impl SysvarSerialize for TestSysvar {} // NOTE tests that use this mock MUST carry the #[serial] attribute struct MockGetSysvarSyscall { @@ -305,16 +277,8 @@ mod tests { let owner = Pubkey::new_unique(); let mut lamports = 42; let mut data = vec![0_u8; TestSysvar::size_of()]; - let mut account_info = AccountInfo::new( - &key, - false, - true, - &mut lamports, - &mut data, - &owner, - false, - Epoch::default(), - ); + let mut account_info = + AccountInfo::new(&key, false, true, &mut lamports, &mut data, &owner, false); test_sysvar.to_account_info(&mut account_info).unwrap(); let new_test_sysvar = TestSysvar::from_account_info(&account_info).unwrap(); diff --git a/sysvar/src/program_stubs.rs b/sysvar/src/program_stubs.rs index 8c76a78a7..ba4180656 100644 --- a/sysvar/src/program_stubs.rs +++ b/sysvar/src/program_stubs.rs @@ -155,12 +155,10 @@ pub(crate) fn sol_get_sysvar( .sol_get_sysvar(sysvar_id_addr, var_addr, offset, length) } -#[cfg(feature = "bincode")] pub(crate) fn sol_get_clock_sysvar(var_addr: *mut u8) -> u64 { SYSCALL_STUBS.read().unwrap().sol_get_clock_sysvar(var_addr) } -#[cfg(feature = "bincode")] pub(crate) fn sol_get_epoch_schedule_sysvar(var_addr: *mut u8) -> u64 { SYSCALL_STUBS .read() @@ -168,17 +166,14 @@ pub(crate) fn sol_get_epoch_schedule_sysvar(var_addr: *mut u8) -> u64 { .sol_get_epoch_schedule_sysvar(var_addr) } -#[cfg(feature = "bincode")] pub(crate) fn sol_get_fees_sysvar(var_addr: *mut u8) -> u64 { SYSCALL_STUBS.read().unwrap().sol_get_fees_sysvar(var_addr) } -#[cfg(feature = "bincode")] pub(crate) fn sol_get_rent_sysvar(var_addr: *mut u8) -> u64 { SYSCALL_STUBS.read().unwrap().sol_get_rent_sysvar(var_addr) } -#[cfg(feature = "bincode")] pub(crate) fn sol_get_last_restart_slot(var_addr: *mut u8) -> u64 { SYSCALL_STUBS .read() @@ -216,7 +211,6 @@ pub fn sol_get_stack_height() -> u64 { SYSCALL_STUBS.read().unwrap().sol_get_stack_height() } -#[cfg(feature = "bincode")] pub(crate) fn sol_get_epoch_rewards_sysvar(var_addr: *mut u8) -> u64 { SYSCALL_STUBS .read() diff --git a/sysvar/src/recent_blockhashes.rs b/sysvar/src/recent_blockhashes.rs index 169507b83..68b0b56e2 100644 --- a/sysvar/src/recent_blockhashes.rs +++ b/sysvar/src/recent_blockhashes.rs @@ -19,11 +19,12 @@ #![allow(deprecated)] #![allow(clippy::arithmetic_side_effects)] #[cfg(feature = "bincode")] -use crate::Sysvar; +use crate::SysvarSerialize; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; pub use solana_sdk_ids::sysvar::recent_blockhashes::{check_id, id, ID}; use { + crate::Sysvar, solana_fee_calculator::FeeCalculator, solana_hash::Hash, solana_sysvar_id::impl_sysvar_id, @@ -150,8 +151,10 @@ impl Iterator for IntoIterSorted { } } +impl Sysvar for RecentBlockhashes {} + #[cfg(feature = "bincode")] -impl Sysvar for RecentBlockhashes { +impl SysvarSerialize for RecentBlockhashes { fn size_of() -> usize { // hard-coded so that we don't have to construct an empty 6008 // golden, update if MAX_ENTRIES changes diff --git a/sysvar/src/rent.rs b/sysvar/src/rent.rs index 368aae008..84f894cf6 100644 --- a/sysvar/src/rent.rs +++ b/sysvar/src/rent.rs @@ -40,7 +40,7 @@ //! # let p = Rent::id(); //! # let l = &mut 1009200; //! # let d = &mut vec![152, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 100]; -//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0); +//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false); //! # let accounts = &[a.clone(), a]; //! # process_instruction( //! # &Pubkey::new_unique(), @@ -55,7 +55,7 @@ //! ``` //! # use solana_account_info::{AccountInfo, next_account_info}; //! # use solana_msg::msg; -//! # use solana_sysvar::Sysvar; +//! # use solana_sysvar::{Sysvar, SysvarSerialize}; //! # use solana_program_error::{ProgramError, ProgramResult}; //! # use solana_pubkey::Pubkey; //! # use solana_rent::Rent; @@ -81,7 +81,7 @@ //! # let p = Rent::id(); //! # let l = &mut 1009200; //! # let d = &mut vec![152, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 100]; -//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false, 0); +//! # let a = AccountInfo::new(&p, false, false, l, d, &p, false); //! # let accounts = &[a.clone(), a]; //! # process_instruction( //! # &Pubkey::new_unique(), @@ -94,9 +94,9 @@ //! Accessing via the RPC client: //! //! ``` -//! # use solana_program::example_mocks::solana_sdk; -//! # use solana_program::example_mocks::solana_rpc_client; -//! # use solana_sdk::account::Account; +//! # use solana_example_mocks::solana_account; +//! # use solana_example_mocks::solana_rpc_client; +//! # use solana_account::Account; //! # use solana_rent::Rent; //! # use solana_rpc_client::rpc_client::RpcClient; //! # use solana_sdk_ids::sysvar::rent; @@ -108,7 +108,6 @@ //! # data: vec![152, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 100], //! # owner: solana_sdk_ids::system_program::ID, //! # executable: false, -//! # rent_epoch: 307, //! # }); //! # //! let rent = client.get_account(&rent::ID)?; @@ -123,13 +122,15 @@ //! # Ok::<(), anyhow::Error>(()) //! ``` #[cfg(feature = "bincode")] +use crate::SysvarSerialize; use crate::{impl_sysvar_get, Sysvar}; pub use { solana_rent::Rent, solana_sdk_ids::sysvar::rent::{check_id, id, ID}, }; - -#[cfg(feature = "bincode")] impl Sysvar for Rent { impl_sysvar_get!(sol_get_rent_sysvar); } + +#[cfg(feature = "bincode")] +impl SysvarSerialize for Rent {} diff --git a/sysvar/src/rewards.rs b/sysvar/src/rewards.rs index 2f8899e5f..0c60e13cb 100644 --- a/sysvar/src/rewards.rs +++ b/sysvar/src/rewards.rs @@ -1,10 +1,10 @@ //! This sysvar is deprecated and unused. #[cfg(feature = "bincode")] -use crate::Sysvar; +use crate::SysvarSerialize; #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; pub use solana_sdk_ids::sysvar::rewards::{check_id, id, ID}; -use solana_sysvar_id::impl_sysvar_id; +use {crate::Sysvar, solana_sysvar_id::impl_sysvar_id}; impl_sysvar_id!(Rewards); @@ -23,5 +23,6 @@ impl Rewards { } } } -#[cfg(feature = "bincode")] impl Sysvar for Rewards {} +#[cfg(feature = "bincode")] +impl SysvarSerialize for Rewards {} diff --git a/sysvar/src/slot_hashes.rs b/sysvar/src/slot_hashes.rs index 75c7aa955..8d14595d0 100644 --- a/sysvar/src/slot_hashes.rs +++ b/sysvar/src/slot_hashes.rs @@ -2,11 +2,11 @@ //! //! The _slot hashes sysvar_ provides access to the [`SlotHashes`] type. //! -//! The [`Sysvar::from_account_info`] and [`Sysvar::get`] methods always return +//! The [`SysvarSerialize::from_account_info`] and [`Sysvar::get`] methods always return //! [`solana_program_error::ProgramError::UnsupportedSysvar`] because this sysvar account is too large //! to process on-chain. Thus this sysvar cannot be accessed on chain, though //! one can still use the [`SysvarId::id`], [`SysvarId::check_id`] and -//! [`Sysvar::size_of`] methods in an on-chain program, and it can be accessed +//! [`SysvarSerialize::size_of`] methods in an on-chain program, and it can be accessed //! off-chain through RPC. //! //! [`SysvarId::id`]: https://docs.rs/solana-sysvar-id/latest/solana_sysvar_id/trait.SysvarId.html#tymethod.id @@ -17,9 +17,9 @@ //! Calling via the RPC client: //! //! ``` -//! # use solana_program::example_mocks::solana_sdk; -//! # use solana_program::example_mocks::solana_rpc_client; -//! # use solana_sdk::account::Account; +//! # use solana_example_mocks::solana_account; +//! # use solana_example_mocks::solana_rpc_client; +//! # use solana_account::Account; //! # use solana_rpc_client::rpc_client::RpcClient; //! # use solana_sdk_ids::sysvar::slot_hashes; //! # use solana_slot_hashes::SlotHashes; @@ -31,7 +31,6 @@ //! # data: vec![1, 0, 0, 0, 0, 0, 0, 0, 86, 190, 235, 7, 0, 0, 0, 0, 133, 242, 94, 158, 223, 253, 207, 184, 227, 194, 235, 27, 176, 98, 73, 3, 175, 201, 224, 111, 21, 65, 73, 27, 137, 73, 229, 19, 255, 192, 193, 126], //! # owner: solana_sdk_ids::system_program::ID, //! # executable: false, -//! # rent_epoch: 307, //! # }); //! # //! let slot_hashes = client.get_account(&slot_hashes::ID)?; @@ -45,12 +44,11 @@ //! # //! # Ok::<(), anyhow::Error>(()) //! ``` - #[cfg(feature = "bytemuck")] use bytemuck_derive::{Pod, Zeroable}; +use {crate::Sysvar, solana_clock::Slot, solana_hash::Hash}; #[cfg(feature = "bincode")] -use {crate::Sysvar, solana_account_info::AccountInfo}; -use {solana_clock::Slot, solana_hash::Hash}; +use {crate::SysvarSerialize, solana_account_info::AccountInfo}; #[cfg(feature = "bytemuck")] const U64_SIZE: usize = std::mem::size_of::(); @@ -64,8 +62,9 @@ pub use { solana_sysvar_id::SysvarId, }; +impl Sysvar for SlotHashes {} #[cfg(feature = "bincode")] -impl Sysvar for SlotHashes { +impl SysvarSerialize for SlotHashes { // override fn size_of() -> usize { // hard-coded so that we don't have to construct an empty @@ -178,55 +177,6 @@ impl PodSlotHashes { } } -/// API for querying the `SlotHashes` sysvar. -#[deprecated(since = "2.1.0", note = "Please use `PodSlotHashes` instead")] -pub struct SlotHashesSysvar; - -#[allow(deprecated)] -impl SlotHashesSysvar { - #[cfg(feature = "bytemuck")] - /// Get a value from the sysvar entries by its key. - /// Returns `None` if the key is not found. - pub fn get(slot: &Slot) -> Result, solana_program_error::ProgramError> { - get_pod_slot_hashes().map(|pod_hashes| { - pod_hashes - .binary_search_by(|PodSlotHash { slot: this, .. }| slot.cmp(this)) - .map(|idx| pod_hashes[idx].hash) - .ok() - }) - } - - #[cfg(feature = "bytemuck")] - /// Get the position of an entry in the sysvar by its key. - /// Returns `None` if the key is not found. - pub fn position(slot: &Slot) -> Result, solana_program_error::ProgramError> { - get_pod_slot_hashes().map(|pod_hashes| { - pod_hashes - .binary_search_by(|PodSlotHash { slot: this, .. }| slot.cmp(this)) - .ok() - }) - } -} - -#[cfg(feature = "bytemuck")] -fn get_pod_slot_hashes() -> Result, solana_program_error::ProgramError> { - let mut pod_hashes = vec![PodSlotHash::default(); solana_slot_hashes::MAX_ENTRIES]; - { - let data = bytemuck::try_cast_slice_mut::(&mut pod_hashes) - .map_err(|_| solana_program_error::ProgramError::InvalidAccountData)?; - - // Ensure the created buffer is aligned to 8. - if data.as_ptr().align_offset(8) != 0 { - return Err(solana_program_error::ProgramError::InvalidAccountData); - } - - let offset = 8; // Vector length as `u64`. - let length = (SYSVAR_LEN as u64).saturating_sub(offset); - crate::get_sysvar(data, &SlotHashes::id(), offset, length)?; - } - Ok(pod_hashes) -} - #[cfg(test)] mod tests { use { @@ -325,58 +275,4 @@ mod tests { ); assert_eq!(pod_slot_hashes.position(¬_a_slot).unwrap(), None); } - - #[allow(deprecated)] - #[serial] - #[test] - fn test_slot_hashes_sysvar() { - let mut slot_hashes = vec![]; - for i in 0..MAX_ENTRIES { - slot_hashes.push(( - i as u64, - hash(&[(i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]), - )); - } - - let check_slot_hashes = SlotHashes::new(&slot_hashes); - mock_get_sysvar_syscall(&bincode::serialize(&check_slot_hashes).unwrap()); - - // `get`: - assert_eq!( - SlotHashesSysvar::get(&0).unwrap().as_ref(), - check_slot_hashes.get(&0), - ); - assert_eq!( - SlotHashesSysvar::get(&256).unwrap().as_ref(), - check_slot_hashes.get(&256), - ); - assert_eq!( - SlotHashesSysvar::get(&511).unwrap().as_ref(), - check_slot_hashes.get(&511), - ); - // `None`. - assert_eq!( - SlotHashesSysvar::get(&600).unwrap().as_ref(), - check_slot_hashes.get(&600), - ); - - // `position`: - assert_eq!( - SlotHashesSysvar::position(&0).unwrap(), - check_slot_hashes.position(&0), - ); - assert_eq!( - SlotHashesSysvar::position(&256).unwrap(), - check_slot_hashes.position(&256), - ); - assert_eq!( - SlotHashesSysvar::position(&511).unwrap(), - check_slot_hashes.position(&511), - ); - // `None`. - assert_eq!( - SlotHashesSysvar::position(&600).unwrap(), - check_slot_hashes.position(&600), - ); - } } diff --git a/sysvar/src/slot_history.rs b/sysvar/src/slot_history.rs index 46ddefe43..6fb38e505 100644 --- a/sysvar/src/slot_history.rs +++ b/sysvar/src/slot_history.rs @@ -2,11 +2,11 @@ //! //! The _slot history sysvar_ provides access to the [`SlotHistory`] type. //! -//! The [`Sysvar::from_account_info`] and [`Sysvar::get`] methods always return +//! The [`SysvarSerialize::from_account_info`] and [`Sysvar::get`] methods always return //! [`ProgramError::UnsupportedSysvar`] because this sysvar account is too large //! to process on-chain. Thus this sysvar cannot be accessed on chain, though //! one can still use the [`SysvarId::id`], [`SysvarId::check_id`] and -//! [`Sysvar::size_of`] methods in an on-chain program, and it can be accessed +//! [`SysvarSerialize::size_of`] methods in an on-chain program, and it can be accessed //! off-chain through RPC. //! //! [`SysvarId::id`]: https://docs.rs/solana-sysvar-id/latest/solana_sysvar_id/trait.SysvarId.html#tymethod.id @@ -17,10 +17,10 @@ //! Calling via the RPC client: //! //! ``` -//! # use solana_program::example_mocks::solana_sdk; -//! # use solana_program::example_mocks::solana_rpc_client; +//! # use solana_example_mocks::solana_account; +//! # use solana_example_mocks::solana_rpc_client; //! # use solana_rpc_client::rpc_client::RpcClient; -//! # use solana_sdk::account::Account; +//! # use solana_account::Account; //! # use solana_slot_history::SlotHistory; //! # use solana_sdk_ids::sysvar::slot_history; //! # use anyhow::Result; @@ -33,7 +33,6 @@ //! # data, //! # owner: solana_sdk_ids::system_program::ID, //! # executable: false, -//! # rent_epoch: 307, //! # }); //! # //! let slot_history = client.get_account(&slot_history::ID)?; @@ -48,17 +47,18 @@ //! # Ok::<(), anyhow::Error>(()) //! ``` -#[cfg(feature = "bincode")] use crate::Sysvar; +#[cfg(feature = "bincode")] +use crate::SysvarSerialize; pub use { solana_account_info::AccountInfo, solana_program_error::ProgramError, solana_sdk_ids::sysvar::slot_history::{check_id, id, ID}, solana_slot_history::SlotHistory, }; - +impl Sysvar for SlotHistory {} #[cfg(feature = "bincode")] -impl Sysvar for SlotHistory { +impl SysvarSerialize for SlotHistory { // override fn size_of() -> usize { // hard-coded so that we don't have to construct an empty diff --git a/sysvar/src/stake_history.rs b/sysvar/src/stake_history.rs deleted file mode 100644 index 9def5ae40..000000000 --- a/sysvar/src/stake_history.rs +++ /dev/null @@ -1,258 +0,0 @@ -//! History of stake activations and de-activations. -//! -//! The _stake history sysvar_ provides access to the [`StakeHistory`] type. -//! -//! The [`Sysvar::get`] method always returns -//! [`ProgramError::UnsupportedSysvar`], and in practice the data size of this -//! sysvar is too large to process on chain. One can still use the -//! [`SysvarId::id`], [`SysvarId::check_id`] and [`Sysvar::size_of`] methods in -//! an on-chain program, and it can be accessed off-chain through RPC. -//! -//! [`ProgramError::UnsupportedSysvar`]: https://docs.rs/solana-program-error/latest/solana_program_error/enum.ProgramError.html#variant.UnsupportedSysvar -//! [`SysvarId::id`]: https://docs.rs/solana-sysvar-id/latest/solana_sysvar_id/trait.SysvarId.html -//! [`SysvarId::check_id`]: https://docs.rs/solana-sysvar-id/latest/solana_sysvar_id/trait.SysvarId.html#tymethod.check_id -//! -//! # Examples -//! -//! Calling via the RPC client: -//! -//! ``` -//! # use solana_program::example_mocks::solana_sdk; -//! # use solana_program::example_mocks::solana_rpc_client; -//! # use solana_program::stake_history::StakeHistory; -//! # use solana_sdk::account::Account; -//! # use solana_rpc_client::rpc_client::RpcClient; -//! # use solana_sdk_ids::sysvar::stake_history; -//! # use anyhow::Result; -//! # -//! fn print_sysvar_stake_history(client: &RpcClient) -> Result<()> { -//! # client.set_get_account_response(stake_history::ID, Account { -//! # lamports: 114979200, -//! # data: vec![0, 0, 0, 0, 0, 0, 0, 0], -//! # owner: solana_sdk_ids::system_program::ID, -//! # executable: false, -//! # rent_epoch: 307, -//! # }); -//! # -//! let stake_history = client.get_account(&stake_history::ID)?; -//! let data: StakeHistory = bincode::deserialize(&stake_history.data)?; -//! -//! Ok(()) -//! } -//! # -//! # let client = RpcClient::new(String::new()); -//! # print_sysvar_stake_history(&client)?; -//! # -//! # Ok::<(), anyhow::Error>(()) -//! ``` - -#[cfg(feature = "bincode")] -use crate::Sysvar; -pub use solana_sdk_ids::sysvar::stake_history::{check_id, id, ID}; -#[deprecated( - since = "2.2.0", - note = "Use solana_stake_interface::stake_history instead" -)] -pub use solana_stake_interface::stake_history::{ - StakeHistory, StakeHistoryEntry, StakeHistoryGetEntry, MAX_ENTRIES, -}; -use {crate::get_sysvar, solana_clock::Epoch}; - -#[cfg(feature = "bincode")] -impl Sysvar for StakeHistory { - // override - fn size_of() -> usize { - // hard-coded so that we don't have to construct an empty - 16392 // golden, update if MAX_ENTRIES changes - } -} - -// we do not provide Default because this requires the real current epoch -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct StakeHistorySysvar(pub Epoch); - -// precompute so we can statically allocate buffer -const EPOCH_AND_ENTRY_SERIALIZED_SIZE: u64 = 32; - -impl StakeHistoryGetEntry for StakeHistorySysvar { - fn get_entry(&self, target_epoch: Epoch) -> Option { - let current_epoch = self.0; - - // if current epoch is zero this returns None because there is no history yet - let newest_historical_epoch = current_epoch.checked_sub(1)?; - let oldest_historical_epoch = current_epoch.saturating_sub(MAX_ENTRIES as u64); - - // target epoch is old enough to have fallen off history; presume fully active/deactive - if target_epoch < oldest_historical_epoch { - return None; - } - - // epoch delta is how many epoch-entries we offset in the stake history vector, which may be zero - // None means target epoch is current or in the future; this is a user error - let epoch_delta = newest_historical_epoch.checked_sub(target_epoch)?; - - // offset is the number of bytes to our desired entry, including eight for vector length - let offset = epoch_delta - .checked_mul(EPOCH_AND_ENTRY_SERIALIZED_SIZE)? - .checked_add(std::mem::size_of::() as u64)?; - - let mut entry_buf = [0; EPOCH_AND_ENTRY_SERIALIZED_SIZE as usize]; - let result = get_sysvar( - &mut entry_buf, - &id(), - offset, - EPOCH_AND_ENTRY_SERIALIZED_SIZE, - ); - - match result { - Ok(()) => { - // All safe because `entry_buf` is a 32-length array - let entry_epoch = u64::from_le_bytes(entry_buf[0..8].try_into().unwrap()); - let effective = u64::from_le_bytes(entry_buf[8..16].try_into().unwrap()); - let activating = u64::from_le_bytes(entry_buf[16..24].try_into().unwrap()); - let deactivating = u64::from_le_bytes(entry_buf[24..32].try_into().unwrap()); - - // this would only fail if stake history skipped an epoch or the binary format of the sysvar changed - assert_eq!(entry_epoch, target_epoch); - - Some(StakeHistoryEntry { - effective, - activating, - deactivating, - }) - } - _ => None, - } - } -} - -#[cfg(test)] -mod tests { - use {super::*, crate::tests::mock_get_sysvar_syscall, serial_test::serial}; - - #[test] - fn test_size_of() { - let mut stake_history = StakeHistory::default(); - for i in 0..MAX_ENTRIES as u64 { - stake_history.add( - i, - StakeHistoryEntry { - activating: i, - ..StakeHistoryEntry::default() - }, - ); - } - - assert_eq!( - bincode::serialized_size(&stake_history).unwrap() as usize, - StakeHistory::size_of() - ); - - let stake_history_inner: Vec<(Epoch, StakeHistoryEntry)> = - bincode::deserialize(&bincode::serialize(&stake_history).unwrap()).unwrap(); - let epoch_entry = stake_history_inner.into_iter().next().unwrap(); - - assert_eq!( - bincode::serialized_size(&epoch_entry).unwrap(), - EPOCH_AND_ENTRY_SERIALIZED_SIZE - ); - } - - #[serial] - #[test] - fn test_stake_history_get_entry() { - let unique_entry_for_epoch = |epoch: u64| StakeHistoryEntry { - activating: epoch.saturating_mul(2), - deactivating: epoch.saturating_mul(3), - effective: epoch.saturating_mul(5), - }; - - let current_epoch = MAX_ENTRIES.saturating_add(2) as u64; - - // make a stake history object with at least one valid entry that has expired - let mut stake_history = StakeHistory::default(); - for i in 0..current_epoch { - stake_history.add(i, unique_entry_for_epoch(i)); - } - assert_eq!(stake_history.len(), MAX_ENTRIES); - assert_eq!(stake_history.iter().map(|entry| entry.0).min().unwrap(), 2); - - // set up sol_get_sysvar - mock_get_sysvar_syscall(&bincode::serialize(&stake_history).unwrap()); - - // make a syscall interface object - let stake_history_sysvar = StakeHistorySysvar(current_epoch); - - // now test the stake history interfaces - - assert_eq!(stake_history.get(0), None); - assert_eq!(stake_history.get(1), None); - assert_eq!(stake_history.get(current_epoch), None); - - assert_eq!(stake_history.get_entry(0), None); - assert_eq!(stake_history.get_entry(1), None); - assert_eq!(stake_history.get_entry(current_epoch), None); - - assert_eq!(stake_history_sysvar.get_entry(0), None); - assert_eq!(stake_history_sysvar.get_entry(1), None); - assert_eq!(stake_history_sysvar.get_entry(current_epoch), None); - - for i in 2..current_epoch { - let entry = Some(unique_entry_for_epoch(i)); - - assert_eq!(stake_history.get(i), entry.as_ref(),); - - assert_eq!(stake_history.get_entry(i), entry,); - - assert_eq!(stake_history_sysvar.get_entry(i), entry,); - } - } - - #[serial] - #[test] - fn test_stake_history_get_entry_zero() { - let mut current_epoch = 0; - - // first test that an empty history returns None - let stake_history = StakeHistory::default(); - assert_eq!(stake_history.len(), 0); - - mock_get_sysvar_syscall(&bincode::serialize(&stake_history).unwrap()); - let stake_history_sysvar = StakeHistorySysvar(current_epoch); - - assert_eq!(stake_history.get(0), None); - assert_eq!(stake_history.get_entry(0), None); - assert_eq!(stake_history_sysvar.get_entry(0), None); - - // next test that we can get a zeroth entry in the first epoch - let entry_zero = StakeHistoryEntry { - effective: 100, - ..StakeHistoryEntry::default() - }; - let entry = Some(entry_zero.clone()); - - let mut stake_history = StakeHistory::default(); - stake_history.add(current_epoch, entry_zero); - assert_eq!(stake_history.len(), 1); - current_epoch = current_epoch.saturating_add(1); - - mock_get_sysvar_syscall(&bincode::serialize(&stake_history).unwrap()); - let stake_history_sysvar = StakeHistorySysvar(current_epoch); - - assert_eq!(stake_history.get(0), entry.as_ref()); - assert_eq!(stake_history.get_entry(0), entry); - assert_eq!(stake_history_sysvar.get_entry(0), entry); - - // finally test that we can still get a zeroth entry in later epochs - stake_history.add(current_epoch, StakeHistoryEntry::default()); - assert_eq!(stake_history.len(), 2); - current_epoch = current_epoch.saturating_add(1); - - mock_get_sysvar_syscall(&bincode::serialize(&stake_history).unwrap()); - let stake_history_sysvar = StakeHistorySysvar(current_epoch); - - assert_eq!(stake_history.get(0), entry.as_ref()); - assert_eq!(stake_history.get_entry(0), entry); - assert_eq!(stake_history_sysvar.get_entry(0), entry); - } -} diff --git a/time-utils/Cargo.toml b/time-utils/Cargo.toml index 17e2ceacf..2dccb71c8 100644 --- a/time-utils/Cargo.toml +++ b/time-utils/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-time-utils" description = "`std::time` utilities for Solana" documentation = "https://docs.rs/solana-time-utils" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/time-utils/src/lib.rs b/time-utils/src/lib.rs index 4cc6caabf..1b2b47091 100644 --- a/time-utils/src/lib.rs +++ b/time-utils/src/lib.rs @@ -4,26 +4,6 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; -#[deprecated(since = "2.1.0", note = "Use `Duration::as_nanos()` directly")] -pub fn duration_as_ns(d: &Duration) -> u64 { - d.as_nanos() as u64 -} - -#[deprecated(since = "2.1.0", note = "Use `Duration::as_micros()` directly")] -pub fn duration_as_us(d: &Duration) -> u64 { - d.as_micros() as u64 -} - -#[deprecated(since = "2.1.0", note = "Use `Duration::as_millis()` directly")] -pub fn duration_as_ms(d: &Duration) -> u64 { - d.as_millis() as u64 -} - -#[deprecated(since = "2.1.0", note = "Use `Duration::as_secs_f32()` directly")] -pub fn duration_as_s(d: &Duration) -> f32 { - d.as_secs_f32() -} - /// return timestamp as ms pub fn timestamp() -> u64 { SystemTime::now() diff --git a/transaction-error/Cargo.toml b/transaction-error/Cargo.toml index 0443a7fdd..a6e7d5db9 100644 --- a/transaction-error/Cargo.toml +++ b/transaction-error/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-transaction-error" description = "Solana TransactionError type" documentation = "https://docs.rs/solana-transaction-error" version = "2.2.1" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -16,16 +17,14 @@ rustdoc-args = ["--cfg=docsrs"] [features] frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"] -serde = ["dep:serde", "dep:serde_derive", "solana-instruction/serde"] +serde = ["dep:serde", "dep:serde_derive", "solana-instruction-error/serde"] [dependencies] serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } solana-frozen-abi = { workspace = true, optional = true } solana-frozen-abi-macro = { workspace = true, optional = true } -solana-instruction = { workspace = true, default-features = false, features = [ - "std", -] } +solana-instruction-error = { workspace = true } solana-sanitize = { workspace = true } [lints] diff --git a/transaction-error/src/lib.rs b/transaction-error/src/lib.rs index 2f5b72b96..849c4c6b3 100644 --- a/transaction-error/src/lib.rs +++ b/transaction-error/src/lib.rs @@ -4,7 +4,7 @@ use serde_derive::{Deserialize, Serialize}; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{AbiEnumVisitor, AbiExample}; -use {core::fmt, solana_instruction::error::InstructionError, solana_sanitize::SanitizeError}; +use {core::fmt, solana_instruction_error::InstructionError, solana_sanitize::SanitizeError}; pub type TransactionResult = Result; @@ -124,7 +124,7 @@ pub enum TransactionError { /// LoadedAccountsDataSizeLimit set for transaction must be greater than 0. InvalidLoadedAccountsDataSizeLimit, - /// Sanitized transaction differed before/after feature activiation. Needs to be resanitized. + /// Sanitized transaction differed before/after feature activation. Needs to be resanitized. ResanitizationNeeded, /// Program execution is temporarily restricted on an account. @@ -142,7 +142,7 @@ pub enum TransactionError { CommitCancelled, } -impl std::error::Error for TransactionError {} +impl core::error::Error for TransactionError {} impl fmt::Display for TransactionError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -268,7 +268,7 @@ pub enum AddressLoaderError { } #[cfg(not(target_os = "solana"))] -impl std::error::Error for AddressLoaderError {} +impl core::error::Error for AddressLoaderError {} #[cfg(not(target_os = "solana"))] impl fmt::Display for AddressLoaderError { @@ -314,8 +314,8 @@ pub enum SanitizeMessageError { } #[cfg(not(target_os = "solana"))] -impl std::error::Error for SanitizeMessageError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { +impl core::error::Error for SanitizeMessageError { + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { match self { Self::IndexOutOfBounds => None, Self::ValueOutOfBounds => None, @@ -365,8 +365,8 @@ pub enum TransportError { } #[cfg(not(target_os = "solana"))] -impl std::error::Error for TransportError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { +impl core::error::Error for TransportError { + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { match self { TransportError::IoError(e) => Some(e), TransportError::TransactionError(e) => Some(e), diff --git a/transaction/Cargo.toml b/transaction/Cargo.toml index 29ebcc86d..bac5e24a6 100644 --- a/transaction/Cargo.toml +++ b/transaction/Cargo.toml @@ -10,27 +10,24 @@ license = { workspace = true } edition = { workspace = true } [package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +targets = ["x86_64-unknown-linux-gnu"] all-features = true rustdoc-args = ["--cfg=docsrs"] [features] bincode = [ "dep:bincode", - "dep:solana-bincode", "dep:solana-signer", - "dep:solana-system-interface", "serde", "solana-message/bincode", ] blake3 = ["bincode", "solana-message/blake3"] -dev-context-only-utils = ["blake3", "precompiles", "serde", "verify"] +dev-context-only-utils = ["blake3", "serde", "verify"] frozen-abi = [ "dep:solana-frozen-abi", "dep:solana-frozen-abi-macro", "dep:solana-logger", ] -precompiles = ["dep:solana-feature-set", "dep:solana-precompiles"] serde = [ "dep:serde", "dep:serde_derive", @@ -44,32 +41,25 @@ verify = ["blake3", "solana-signature/verify"] bincode = { workspace = true, optional = true } serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } -solana-bincode = { workspace = true, optional = true } -solana-feature-set = { workspace = true, optional = true } solana-frozen-abi = { workspace = true, optional = true } solana-frozen-abi-macro = { workspace = true, optional = true } solana-hash = { workspace = true } solana-instruction = { workspace = true } solana-logger = { workspace = true, optional = true } solana-message = { workspace = true } -solana-precompiles = { workspace = true, optional = true } solana-pubkey = { workspace = true } solana-sanitize = { workspace = true } solana-sdk-ids = { workspace = true } solana-short-vec = { workspace = true, optional = true } solana-signature = { workspace = true } solana-signer = { workspace = true, optional = true } -solana-system-interface = { workspace = true, optional = true, features = ["bincode"] } solana-transaction-error = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -solana-keypair = { workspace = true } -wasm-bindgen = { workspace = true } - [dev-dependencies] anyhow = { workspace = true } bincode = { workspace = true } borsh = { workspace = true } +solana-example-mocks = { path = "../example-mocks" } solana-hash = { workspace = true } solana-instruction = { workspace = true, features = ["borsh"] } solana-keypair = { workspace = true } @@ -77,8 +67,8 @@ solana-nonce = { workspace = true } solana-packet = { workspace = true } solana-presigner = { workspace = true } solana-pubkey = { workspace = true, features = ["rand"] } -solana-sdk = { path = "../sdk" } solana-sha256-hasher = { workspace = true } +solana-system-interface = { workspace = true, features = ["bincode"] } solana-transaction = { path = ".", features = ["dev-context-only-utils"] } -solana-vote-interface = { workspace = true } +solana-vote-interface = { workspace = true, features = ["bincode"] } static_assertions = { workspace = true } diff --git a/transaction/src/lib.rs b/transaction/src/lib.rs index 56611a4c4..0bc14bbf5 100644 --- a/transaction/src/lib.rs +++ b/transaction/src/lib.rs @@ -55,7 +55,7 @@ //! [`anyhow`]: https://docs.rs/anyhow //! //! ``` -//! # use solana_sdk::example_mocks::solana_rpc_client; +//! # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; //! use anyhow::Result; //! use borsh::{BorshSerialize, BorshDeserialize}; //! use solana_instruction::Instruction; @@ -110,8 +110,6 @@ //! # Ok::<(), anyhow::Error>(()) //! ``` -#[cfg(target_arch = "wasm32")] -use wasm_bindgen::prelude::wasm_bindgen; #[cfg(feature = "serde")] use { serde_derive::{Deserialize, Serialize}, @@ -119,18 +117,18 @@ use { }; #[cfg(feature = "bincode")] use { - solana_bincode::limited_deserialize, solana_hash::Hash, - solana_message::compiled_instruction::CompiledInstruction, - solana_sdk_ids::system_program, solana_signer::{signers::Signers, SignerError}, - solana_system_interface::instruction::SystemInstruction, }; use { solana_instruction::Instruction, - solana_message::Message, + solana_message::{ + compiled_instruction::CompiledInstruction, inline_nonce::is_advance_nonce_instruction_data, + Message, + }, solana_pubkey::Pubkey, solana_sanitize::{Sanitize, SanitizeError}, + solana_sdk_ids::system_program, solana_signature::Signature, solana_transaction_error::{TransactionError, TransactionResult as Result}, std::result, @@ -139,7 +137,6 @@ use { pub mod sanitized; pub mod simple_vote_transaction_checker; pub mod versioned; -mod wasm; #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum TransactionVerificationMode { @@ -154,13 +151,7 @@ static_assertions::const_assert_eq!( NONCED_TX_MARKER_IX_INDEX, solana_nonce::NONCED_TX_MARKER_IX_INDEX ); -#[cfg(feature = "bincode")] const NONCED_TX_MARKER_IX_INDEX: u8 = 0; -// inlined to avoid solana-packet dep -#[cfg(test)] -static_assertions::const_assert_eq!(PACKET_DATA_SIZE, solana_packet::PACKET_DATA_SIZE); -#[cfg(feature = "bincode")] -const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; /// An atomically-committed sequence of instructions. /// @@ -182,11 +173,10 @@ const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; /// if the caller has knowledge that the first account of the constructed /// transaction's `Message` is both a signer and the expected fee-payer, then /// redundantly specifying the fee-payer is not strictly required. -#[cfg(not(target_arch = "wasm32"))] #[cfg_attr( feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample), - solana_frozen_abi_macro::frozen_abi(digest = "76BDTr3Xm3VP7h4eSiw6pZHKc5yYewDufyia3Yedh6GG") + solana_frozen_abi_macro::frozen_abi(digest = "KSndwV1Ezw3xDX3Mz4Sg2vY22dx9mGTCFzo1RxbwaV8") )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, PartialEq, Default, Eq, Clone)] @@ -207,27 +197,6 @@ pub struct Transaction { pub message: Message, } -/// wasm-bindgen version of the Transaction struct. -/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671 -/// is fixed. This must not diverge from the regular non-wasm Transaction struct. -#[cfg(target_arch = "wasm32")] -#[wasm_bindgen] -#[cfg_attr( - feature = "frozen-abi", - derive(AbiExample), - frozen_abi(digest = "H7xQFcd1MtMv9QKZWGatBAXwhg28tpeX59P3s8ZZLAY4") -)] -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[derive(Debug, PartialEq, Default, Eq, Clone)] -pub struct Transaction { - #[wasm_bindgen(skip)] - #[cfg_attr(feature = "serde", serde(with = "short_vec"))] - pub signatures: Vec, - - #[wasm_bindgen(skip)] - pub message: Message, -} - impl Sanitize for Transaction { fn sanitize(&self) -> result::Result<(), SanitizeError> { if self.message.header.num_required_signatures as usize > self.signatures.len() { @@ -251,7 +220,7 @@ impl Transaction { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_sdk::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_instruction::Instruction; @@ -329,7 +298,7 @@ impl Transaction { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_sdk::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_instruction::Instruction; @@ -408,7 +377,7 @@ impl Transaction { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_sdk::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_instruction::Instruction; @@ -483,7 +452,7 @@ impl Transaction { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_sdk::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_instruction::Instruction; @@ -693,7 +662,7 @@ impl Transaction { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_sdk::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_instruction::Instruction; @@ -833,7 +802,7 @@ impl Transaction { /// [`anyhow`]: https://docs.rs/anyhow /// /// ``` - /// # use solana_sdk::example_mocks::solana_rpc_client; + /// # use solana_example_mocks::{solana_keypair, solana_rpc_client, solana_signer, solana_transaction}; /// use anyhow::Result; /// use borsh::{BorshSerialize, BorshDeserialize}; /// use solana_instruction::Instruction; @@ -1057,29 +1026,6 @@ impl Transaction { .collect() } - #[cfg(feature = "precompiles")] - #[deprecated(since = "2.2.3", note = "Use agave-precompiles instead")] - #[allow(deprecated)] - /// Verify the precompiled programs in this transaction. - pub fn verify_precompiles(&self, feature_set: &solana_feature_set::FeatureSet) -> Result<()> { - for instruction in &self.message().instructions { - // The Transaction may not be sanitized at this point - if instruction.program_id_index as usize >= self.message().account_keys.len() { - return Err(TransactionError::AccountNotFound); - } - let program_id = &self.message().account_keys[instruction.program_id_index as usize]; - - solana_precompiles::verify_if_precompile( - program_id, - instruction, - &self.message().instructions, - feature_set, - ) - .map_err(|_| TransactionError::InvalidAccountIndex)?; - } - Ok(()) - } - /// Get the positions of the pubkeys in `account_keys` associated with signing keypairs. /// /// [`account_keys`]: Message::account_keys @@ -1133,7 +1079,6 @@ impl Transaction { } } -#[cfg(feature = "bincode")] /// Returns true if transaction begins with an advance nonce instruction. pub fn uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstruction> { let message = tx.message(); @@ -1145,12 +1090,7 @@ pub fn uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstruction> { matches!( message.account_keys.get(instruction.program_id_index as usize), Some(program_id) if system_program::check_id(program_id) - ) - // Is a nonce advance instruction - && matches!( - limited_deserialize(&instruction.data, PACKET_DATA_SIZE as u64), - Ok(SystemInstruction::AdvanceNonceAccount) - ) + ) && is_advance_nonce_instruction_data(&instruction.data) }) } @@ -1308,12 +1248,15 @@ mod tests { } fn create_sample_transaction() -> Transaction { - let keypair = Keypair::from_bytes(&[ - 255, 101, 36, 24, 124, 23, 167, 21, 132, 204, 155, 5, 185, 58, 121, 75, 156, 227, 116, - 193, 215, 38, 142, 22, 8, 14, 229, 239, 119, 93, 5, 218, 36, 100, 158, 252, 33, 161, - 97, 185, 62, 89, 99, 195, 250, 249, 187, 189, 171, 118, 241, 90, 248, 14, 68, 219, 231, - 62, 157, 5, 142, 27, 210, 117, - ]) + let keypair = Keypair::try_from( + [ + 255, 101, 36, 24, 124, 23, 167, 21, 132, 204, 155, 5, 185, 58, 121, 75, 156, 227, + 116, 193, 215, 38, 142, 22, 8, 14, 229, 239, 119, 93, 5, 218, 36, 100, 158, 252, + 33, 161, 97, 185, 62, 89, 99, 195, 250, 249, 187, 189, 171, 118, 241, 90, 248, 14, + 68, 219, 231, 62, 157, 5, 142, 27, 210, 117, + ] + .as_ref(), + ) .unwrap(); let to = Pubkey::from([ 1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, diff --git a/transaction/src/sanitized.rs b/transaction/src/sanitized.rs index aa6b0dad5..638885be3 100644 --- a/transaction/src/sanitized.rs +++ b/transaction/src/sanitized.rs @@ -216,13 +216,13 @@ impl SanitizedTransaction { pub fn get_account_locks( &self, tx_account_lock_limit: usize, - ) -> Result { + ) -> Result> { Self::validate_account_locks(self.message(), tx_account_lock_limit)?; Ok(self.get_account_locks_unchecked()) } /// Return the list of accounts that must be locked during processing this transaction. - pub fn get_account_locks_unchecked(&self) -> TransactionAccountLocks { + pub fn get_account_locks_unchecked(&self) -> TransactionAccountLocks<'_> { let message = &self.message; let account_keys = message.account_keys(); let num_readonly_accounts = message.num_readonly_accounts(); @@ -284,30 +284,6 @@ impl SanitizedTransaction { } } - #[cfg(feature = "precompiles")] - #[deprecated(since = "2.2.3", note = "Use agave-precompiles instead")] - #[allow(deprecated)] - /// Verify the precompiled programs in this transaction - pub fn verify_precompiles(&self, feature_set: &solana_feature_set::FeatureSet) -> Result<()> { - for (index, (program_id, instruction)) in - self.message.program_instructions_iter().enumerate() - { - solana_precompiles::verify_if_precompile( - program_id, - instruction, - self.message().instructions(), - feature_set, - ) - .map_err(|err| { - TransactionError::InstructionError( - index as u8, - solana_instruction::error::InstructionError::Custom(err as u32), - ) - })?; - } - Ok(()) - } - /// Validate a transaction message against locked accounts pub fn validate_account_locks( message: &SanitizedMessage, diff --git a/transaction/src/versioned/mod.rs b/transaction/src/versioned/mod.rs index 21f8be087..cb6b78a47 100644 --- a/transaction/src/versioned/mod.rs +++ b/transaction/src/versioned/mod.rs @@ -1,21 +1,20 @@ //! Defines a transaction which supports multiple versions of messages. +#[cfg(feature = "bincode")] +use solana_signer::{signers::Signers, SignerError}; use { - crate::Transaction, solana_message::VersionedMessage, solana_sanitize::SanitizeError, - solana_signature::Signature, std::cmp::Ordering, + crate::Transaction, + solana_message::{inline_nonce::is_advance_nonce_instruction_data, VersionedMessage}, + solana_sanitize::SanitizeError, + solana_sdk_ids::system_program, + solana_signature::Signature, + std::cmp::Ordering, }; #[cfg(feature = "serde")] use { serde_derive::{Deserialize, Serialize}, solana_short_vec as short_vec, }; -#[cfg(feature = "bincode")] -use { - solana_bincode::limited_deserialize, - solana_sdk_ids::system_program, - solana_signer::{signers::Signers, SignerError}, - solana_system_interface::instruction::SystemInstruction, -}; pub mod sanitized; @@ -204,7 +203,6 @@ impl VersionedTransaction { .collect() } - #[cfg(feature = "bincode")] /// Returns true if transaction begins with an advance nonce instruction. pub fn uses_durable_nonce(&self) -> bool { let message = &self.message; @@ -216,12 +214,7 @@ impl VersionedTransaction { matches!( message.static_account_keys().get(instruction.program_id_index as usize), Some(program_id) if system_program::check_id(program_id) - ) - // Is a nonce advance instruction - && matches!( - limited_deserialize(&instruction.data, crate::PACKET_DATA_SIZE as u64,), - Ok(SystemInstruction::AdvanceNonceAccount) - ) + ) && is_advance_nonce_instruction_data(&instruction.data) }) .is_some() } diff --git a/transaction/src/wasm.rs b/transaction/src/wasm.rs deleted file mode 100644 index cdfc5792b..000000000 --- a/transaction/src/wasm.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! `Transaction` Javascript interface -#![cfg(target_arch = "wasm32")] -#![allow(non_snake_case)] -use { - crate::Transaction, solana_hash::Hash, solana_instruction::wasm::Instructions, - solana_keypair::Keypair, solana_message::Message, solana_pubkey::Pubkey, - wasm_bindgen::prelude::*, -}; - -#[wasm_bindgen] -impl Transaction { - /// Create a new `Transaction` - #[wasm_bindgen(constructor)] - pub fn constructor(instructions: Instructions, payer: Option) -> Transaction { - let instructions: Vec<_> = instructions.into(); - Transaction::new_with_payer(&instructions, payer.as_ref()) - } - - /// Return a message containing all data that should be signed. - #[wasm_bindgen(js_name = message)] - pub fn js_message(&self) -> Message { - self.message.clone() - } - - /// Return the serialized message data to sign. - pub fn messageData(&self) -> Box<[u8]> { - self.message_data().into() - } - - #[cfg(feature = "verify")] - /// Verify the transaction - #[wasm_bindgen(js_name = verify)] - pub fn js_verify(&self) -> Result<(), JsValue> { - self.verify() - .map_err(|x| std::string::ToString::to_string(&x).into()) - } - - pub fn partialSign(&mut self, keypair: &Keypair, recent_blockhash: &Hash) { - self.partial_sign(&[keypair], *recent_blockhash); - } - - pub fn isSigned(&self) -> bool { - self.is_signed() - } - - #[cfg(feature = "bincode")] - pub fn toBytes(&self) -> Box<[u8]> { - bincode::serialize(self).unwrap().into() - } - - #[cfg(feature = "bincode")] - pub fn fromBytes(bytes: &[u8]) -> Result { - bincode::deserialize(bytes).map_err(|x| std::string::ToString::to_string(&x).into()) - } -} diff --git a/validator-exit/Cargo.toml b/validator-exit/Cargo.toml index c1af5810c..01307037c 100644 --- a/validator-exit/Cargo.toml +++ b/validator-exit/Cargo.toml @@ -2,7 +2,7 @@ name = "solana-validator-exit" description = "Solana validator exit handling." documentation = "https://docs.rs/solana-validator-exit" -version = "2.2.1" +version = "3.0.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } diff --git a/vote-interface/Cargo.toml b/vote-interface/Cargo.toml index 0b6993704..fba9deaf1 100644 --- a/vote-interface/Cargo.toml +++ b/vote-interface/Cargo.toml @@ -3,6 +3,7 @@ name = "solana-vote-interface" description = "Solana vote interface." documentation = "https://docs.rs/solana-vote-interface" version = "2.2.5" +rust-version = "1.81.0" authors = { workspace = true } repository = { workspace = true } homepage = { workspace = true } @@ -51,7 +52,6 @@ num-traits = { workspace = true } serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } solana-clock = { workspace = true } -solana-decode-error = { workspace = true } solana-frozen-abi = { workspace = true, features = [ "frozen-abi", ], optional = true } @@ -60,6 +60,7 @@ solana-frozen-abi-macro = { workspace = true, features = [ ], optional = true } solana-hash = { workspace = true } solana-instruction = { workspace = true, features = ["std"] } +solana-instruction-error = { workspace = true, features = ["num-traits"] } solana-pubkey = { workspace = true } solana-rent = { workspace = true } solana-sdk-ids = { workspace = true } diff --git a/vote-interface/src/authorized_voters.rs b/vote-interface/src/authorized_voters.rs index f36c1300c..cb47e89ff 100644 --- a/vote-interface/src/authorized_voters.rs +++ b/vote-interface/src/authorized_voters.rs @@ -80,7 +80,7 @@ impl AuthorizedVoters { self.authorized_voters.contains_key(&epoch) } - pub fn iter(&self) -> std::collections::btree_map::Iter { + pub fn iter(&self) -> std::collections::btree_map::Iter<'_, Epoch, Pubkey> { self.authorized_voters.iter() } diff --git a/vote-interface/src/error.rs b/vote-interface/src/error.rs index 46b27747c..573c13cbd 100644 --- a/vote-interface/src/error.rs +++ b/vote-interface/src/error.rs @@ -32,7 +32,7 @@ pub enum VoteError { AssertionFailed, } -impl std::error::Error for VoteError {} +impl core::error::Error for VoteError {} impl fmt::Display for VoteError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -71,42 +71,3 @@ impl fmt::Display for VoteError { }) } } - -#[allow(deprecated)] -impl solana_decode_error::DecodeError for VoteError { - fn type_of() -> &'static str { - "VoteError" - } -} - -#[cfg(test)] -mod tests { - use {super::*, solana_instruction::error::InstructionError}; - - #[test] - fn test_custom_error_decode() { - use num_traits::FromPrimitive; - #[allow(deprecated)] - fn pretty_err(err: InstructionError) -> String - where - T: 'static + std::error::Error + solana_decode_error::DecodeError + FromPrimitive, - { - if let InstructionError::Custom(code) = err { - let specific_error: T = T::decode_custom_error_to_enum(code).unwrap(); - format!( - "{:?}: {}::{:?} - {}", - err, - T::type_of(), - specific_error, - specific_error, - ) - } else { - "".to_string() - } - } - assert_eq!( - "Custom(0): VoteError::VoteTooOld - vote already recorded or not in slot hashes history", - pretty_err::(VoteError::VoteTooOld.into()) - ) - } -} diff --git a/vote-interface/src/state/mod.rs b/vote-interface/src/state/mod.rs index e98ecfdd6..85c028923 100644 --- a/vote-interface/src/state/mod.rs +++ b/vote-interface/src/state/mod.rs @@ -22,7 +22,7 @@ pub use vote_state_1_14_11::*; pub mod vote_state_versions; pub use vote_state_versions::*; pub mod vote_state_v3; -pub use vote_state_v3::VoteState; +pub use vote_state_v3::VoteStateV3; mod vote_instruction_data; pub use vote_instruction_data::*; @@ -391,22 +391,22 @@ mod tests { use { super::*, crate::error::VoteError, bincode::serialized_size, core::mem::MaybeUninit, itertools::Itertools, rand::Rng, solana_clock::Clock, solana_hash::Hash, - solana_instruction::error::InstructionError, + solana_instruction_error::InstructionError, }; #[test] fn test_vote_serialize() { - let mut buffer: Vec = vec![0; VoteState::size_of()]; - let mut vote_state = VoteState::default(); + let mut buffer: Vec = vec![0; VoteStateV3::size_of()]; + let mut vote_state = VoteStateV3::default(); vote_state .votes .resize(MAX_LOCKOUT_HISTORY, LandedVote::default()); vote_state.root_slot = Some(1); let versioned = VoteStateVersions::new_current(vote_state); - assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err()); - VoteState::serialize(&versioned, &mut buffer).unwrap(); + assert!(VoteStateV3::serialize(&versioned, &mut buffer[0..4]).is_err()); + VoteStateV3::serialize(&versioned, &mut buffer).unwrap(); assert_eq!( - VoteState::deserialize(&buffer).unwrap(), + VoteStateV3::deserialize(&buffer).unwrap(), versioned.convert_to_current() ); } @@ -414,18 +414,18 @@ mod tests { #[test] fn test_vote_deserialize_into() { // base case - let target_vote_state = VoteState::default(); + let target_vote_state = VoteStateV3::default(); let vote_state_buf = bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap(); - let mut test_vote_state = VoteState::default(); - VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap(); + let mut test_vote_state = VoteStateV3::default(); + VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap(); assert_eq!(target_vote_state, test_vote_state); // variant // provide 4x the minimum struct size in bytes to ensure we typically touch every field - let struct_bytes_x4 = std::mem::size_of::() * 4; + let struct_bytes_x4 = std::mem::size_of::() * 4; for _ in 0..1000 { let raw_data: Vec = (0..struct_bytes_x4).map(|_| rand::random::()).collect(); let mut unstructured = Unstructured::new(&raw_data); @@ -435,8 +435,8 @@ mod tests { let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap(); let target_vote_state = target_vote_state_versions.convert_to_current(); - let mut test_vote_state = VoteState::default(); - VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap(); + let mut test_vote_state = VoteStateV3::default(); + VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap(); assert_eq!(target_vote_state, test_vote_state); } @@ -444,33 +444,33 @@ mod tests { #[test] fn test_vote_deserialize_into_error() { - let target_vote_state = VoteState::new_rand_for_tests(Pubkey::new_unique(), 42); + let target_vote_state = VoteStateV3::new_rand_for_tests(Pubkey::new_unique(), 42); let mut vote_state_buf = bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap(); let len = vote_state_buf.len(); vote_state_buf.truncate(len - 1); - let mut test_vote_state = VoteState::default(); - VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap_err(); - assert_eq!(test_vote_state, VoteState::default()); + let mut test_vote_state = VoteStateV3::default(); + VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap_err(); + assert_eq!(test_vote_state, VoteStateV3::default()); } #[test] fn test_vote_deserialize_into_uninit() { // base case - let target_vote_state = VoteState::default(); + let target_vote_state = VoteStateV3::default(); let vote_state_buf = bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap(); let mut test_vote_state = MaybeUninit::uninit(); - VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); + VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); let test_vote_state = unsafe { test_vote_state.assume_init() }; assert_eq!(target_vote_state, test_vote_state); // variant // provide 4x the minimum struct size in bytes to ensure we typically touch every field - let struct_bytes_x4 = std::mem::size_of::() * 4; + let struct_bytes_x4 = std::mem::size_of::() * 4; for _ in 0..1000 { let raw_data: Vec = (0..struct_bytes_x4).map(|_| rand::random::()).collect(); let mut unstructured = Unstructured::new(&raw_data); @@ -481,7 +481,7 @@ mod tests { let target_vote_state = target_vote_state_versions.convert_to_current(); let mut test_vote_state = MaybeUninit::uninit(); - VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); + VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); let test_vote_state = unsafe { test_vote_state.assume_init() }; assert_eq!(target_vote_state, test_vote_state); @@ -492,11 +492,11 @@ mod tests { fn test_vote_deserialize_into_uninit_nopanic() { // base case let mut test_vote_state = MaybeUninit::uninit(); - let e = VoteState::deserialize_into_uninit(&[], &mut test_vote_state).unwrap_err(); + let e = VoteStateV3::deserialize_into_uninit(&[], &mut test_vote_state).unwrap_err(); assert_eq!(e, InstructionError::InvalidAccountData); // variant - let serialized_len_x4 = serialized_size(&VoteState::default()).unwrap() * 4; + let serialized_len_x4 = serialized_size(&VoteStateV3::default()).unwrap() * 4; let mut rng = rand::thread_rng(); for _ in 0..1000 { let raw_data_length = rng.gen_range(1..serialized_len_x4); @@ -514,7 +514,7 @@ mod tests { // it is extremely improbable, though theoretically possible, for random bytes to be syntactically valid // so we only check that the parser does not panic and that it succeeds or fails exactly in line with bincode let mut test_vote_state = MaybeUninit::uninit(); - let test_res = VoteState::deserialize_into_uninit(&raw_data, &mut test_vote_state); + let test_res = VoteStateV3::deserialize_into_uninit(&raw_data, &mut test_vote_state); let bincode_res = bincode::deserialize::(&raw_data) .map(|versioned| versioned.convert_to_current()); @@ -530,7 +530,7 @@ mod tests { #[test] fn test_vote_deserialize_into_uninit_ill_sized() { // provide 4x the minimum struct size in bytes to ensure we typically touch every field - let struct_bytes_x4 = std::mem::size_of::() * 4; + let struct_bytes_x4 = std::mem::size_of::() * 4; for _ in 0..1000 { let raw_data: Vec = (0..struct_bytes_x4).map(|_| rand::random::()).collect(); let mut unstructured = Unstructured::new(&raw_data); @@ -547,7 +547,8 @@ mod tests { // truncated fails let mut test_vote_state = MaybeUninit::uninit(); - let test_res = VoteState::deserialize_into_uninit(&truncated_buf, &mut test_vote_state); + let test_res = + VoteStateV3::deserialize_into_uninit(&truncated_buf, &mut test_vote_state); let bincode_res = bincode::deserialize::(&truncated_buf) .map(|versioned| versioned.convert_to_current()); @@ -556,7 +557,7 @@ mod tests { // expanded succeeds let mut test_vote_state = MaybeUninit::uninit(); - VoteState::deserialize_into_uninit(&expanded_buf, &mut test_vote_state).unwrap(); + VoteStateV3::deserialize_into_uninit(&expanded_buf, &mut test_vote_state).unwrap(); let bincode_res = bincode::deserialize::(&expanded_buf) .map(|versioned| versioned.convert_to_current()); @@ -565,34 +566,9 @@ mod tests { } } - #[test] - #[allow(deprecated)] - fn test_vote_state_commission_split() { - let vote_state = VoteState::default(); - - assert_eq!(vote_state.commission_split(1), (0, 1, false)); - - let mut vote_state = VoteState { - commission: u8::MAX, - ..VoteState::default() - }; - assert_eq!(vote_state.commission_split(1), (1, 0, false)); - - vote_state.commission = 99; - assert_eq!(vote_state.commission_split(10), (9, 0, true)); - - vote_state.commission = 1; - assert_eq!(vote_state.commission_split(10), (0, 9, true)); - - vote_state.commission = 50; - let (voter_portion, staker_portion, was_split) = vote_state.commission_split(10); - - assert_eq!((voter_portion, staker_portion, was_split), (5, 5, true)); - } - #[test] fn test_vote_state_epoch_credits() { - let mut vote_state = VoteState::default(); + let mut vote_state = VoteStateV3::default(); assert_eq!(vote_state.credits(), 0); assert_eq!(vote_state.epoch_credits().clone(), vec![]); @@ -618,7 +594,7 @@ mod tests { #[test] fn test_vote_state_epoch0_no_credits() { - let mut vote_state = VoteState::default(); + let mut vote_state = VoteStateV3::default(); assert_eq!(vote_state.epoch_credits().len(), 0); vote_state.increment_credits(1, 1); @@ -630,7 +606,7 @@ mod tests { #[test] fn test_vote_state_increment_credits() { - let mut vote_state = VoteState::default(); + let mut vote_state = VoteStateV3::default(); let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64; for i in 0..credits { @@ -643,9 +619,9 @@ mod tests { #[test] fn test_vote_process_timestamp() { let (slot, timestamp) = (15, 1_575_412_285); - let mut vote_state = VoteState { + let mut vote_state = VoteStateV3 { last_timestamp: BlockTimestamp { slot, timestamp }, - ..VoteState::default() + ..VoteStateV3::default() }; assert_eq!( @@ -697,7 +673,7 @@ mod tests { #[test] fn test_get_and_update_authorized_voter() { let original_voter = Pubkey::new_unique(); - let mut vote_state = VoteState::new( + let mut vote_state = VoteStateV3::new( &VoteInit { node_pubkey: original_voter, authorized_voter: original_voter, @@ -764,7 +740,7 @@ mod tests { fn test_set_new_authorized_voter() { let original_voter = Pubkey::new_unique(); let epoch_offset = 15; - let mut vote_state = VoteState::new( + let mut vote_state = VoteStateV3::new( &VoteInit { node_pubkey: original_voter, authorized_voter: original_voter, @@ -862,7 +838,7 @@ mod tests { #[test] fn test_authorized_voter_is_locked_within_epoch() { let original_voter = Pubkey::new_unique(); - let mut vote_state = VoteState::new( + let mut vote_state = VoteStateV3::new( &VoteInit { node_pubkey: original_voter, authorized_voter: original_voter, @@ -902,16 +878,16 @@ mod tests { #[test] fn test_vote_state_size_of() { - let vote_state = VoteState::get_max_sized_vote_state(); + let vote_state = VoteStateV3::get_max_sized_vote_state(); let vote_state = VoteStateVersions::new_current(vote_state); let size = serialized_size(&vote_state).unwrap(); - assert_eq!(VoteState::size_of() as u64, size); + assert_eq!(VoteStateV3::size_of() as u64, size); } #[test] fn test_vote_state_max_size() { - let mut max_sized_data = vec![0; VoteState::size_of()]; - let vote_state = VoteState::get_max_sized_vote_state(); + let mut max_sized_data = vec![0; VoteStateV3::size_of()]; + let vote_state = VoteStateV3::get_max_sized_vote_state(); let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap(); let start_current_epoch = start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1; @@ -928,17 +904,17 @@ mod tests { }); let versioned = VoteStateVersions::new_current(vote_state.take().unwrap()); - VoteState::serialize(&versioned, &mut max_sized_data).unwrap(); + VoteStateV3::serialize(&versioned, &mut max_sized_data).unwrap(); vote_state = Some(versioned.convert_to_current()); } } #[test] fn test_default_vote_state_is_uninitialized() { - // The default `VoteState` is stored to de-initialize a zero-balance vote account, + // The default `VoteStateV3` is stored to de-initialize a zero-balance vote account, // so must remain such that `VoteStateVersions::is_uninitialized()` returns true // when called on a `VoteStateVersions` that stores it - assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized()); + assert!(VoteStateVersions::new_current(VoteStateV3::default()).is_uninitialized()); } #[test] @@ -949,9 +925,9 @@ mod tests { &vote_account_data )); - // Check default VoteState - let default_account_state = VoteStateVersions::new_current(VoteState::default()); - VoteState::serialize(&default_account_state, &mut vote_account_data).unwrap(); + // Check default VoteStateV3 + let default_account_state = VoteStateVersions::new_current(VoteStateV3::default()); + VoteStateV3::serialize(&default_account_state, &mut vote_account_data).unwrap(); assert!(!VoteStateVersions::is_correct_size_and_initialized( &vote_account_data )); @@ -964,14 +940,14 @@ mod tests { // Check non-zero large account let mut large_vote_data = vec![1; 2 * VoteStateVersions::vote_state_size_of(true)]; - let default_account_state = VoteStateVersions::new_current(VoteState::default()); - VoteState::serialize(&default_account_state, &mut large_vote_data).unwrap(); + let default_account_state = VoteStateVersions::new_current(VoteStateV3::default()); + VoteStateV3::serialize(&default_account_state, &mut large_vote_data).unwrap(); assert!(!VoteStateVersions::is_correct_size_and_initialized( &vote_account_data )); - // Check populated VoteState - let vote_state = VoteState::new( + // Check populated VoteStateV3 + let vote_state = VoteStateV3::new( &VoteInit { node_pubkey: Pubkey::new_unique(), authorized_voter: Pubkey::new_unique(), @@ -981,16 +957,16 @@ mod tests { &Clock::default(), ); let account_state = VoteStateVersions::new_current(vote_state.clone()); - VoteState::serialize(&account_state, &mut vote_account_data).unwrap(); + VoteStateV3::serialize(&account_state, &mut vote_account_data).unwrap(); assert!(VoteStateVersions::is_correct_size_and_initialized( &vote_account_data )); - // Check old VoteState that hasn't been upgraded to newest version yet + // Check old VoteStateV3 that hasn't been upgraded to newest version yet let old_vote_state = VoteState1_14_11::from(vote_state); let account_state = VoteStateVersions::V1_14_11(Box::new(old_vote_state)); let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(false)]; - VoteState::serialize(&account_state, &mut vote_account_data).unwrap(); + VoteStateV3::serialize(&account_state, &mut vote_account_data).unwrap(); assert!(VoteStateVersions::is_correct_size_and_initialized( &vote_account_data )); @@ -999,7 +975,7 @@ mod tests { #[test] fn test_minimum_balance() { let rent = solana_rent::Rent::default(); - let minimum_balance = rent.minimum_balance(VoteState::size_of()); + let minimum_balance = rent.minimum_balance(VoteStateV3::size_of()); // golden, may need updating when vote_state grows assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04) } diff --git a/vote-interface/src/state/vote_state_0_23_5.rs b/vote-interface/src/state/vote_state_0_23_5.rs index c3977ae5d..20fefc7f9 100644 --- a/vote-interface/src/state/vote_state_0_23_5.rs +++ b/vote-interface/src/state/vote_state_0_23_5.rs @@ -78,7 +78,7 @@ mod tests { let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap(); let mut test_vote_state = MaybeUninit::uninit(); - VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); + VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); let test_vote_state = unsafe { test_vote_state.assume_init() }; assert_eq!( @@ -101,7 +101,7 @@ mod tests { let target_vote_state = target_vote_state_versions.convert_to_current(); let mut test_vote_state = MaybeUninit::uninit(); - VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); + VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); let test_vote_state = unsafe { test_vote_state.assume_init() }; assert_eq!(target_vote_state, test_vote_state); diff --git a/vote-interface/src/state/vote_state_1_14_11.rs b/vote-interface/src/state/vote_state_1_14_11.rs index 4f8784e13..f68cd11b4 100644 --- a/vote-interface/src/state/vote_state_1_14_11.rs +++ b/vote-interface/src/state/vote_state_1_14_11.rs @@ -7,7 +7,7 @@ const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 82; #[cfg_attr( feature = "frozen-abi", - solana_frozen_abi_macro::frozen_abi(digest = "HF4NfshaLg9e93RURYWTJRowtRrpLf5mWiF4G2Gnfu2r"), + solana_frozen_abi_macro::frozen_abi(digest = "2rjXSWaNeAdoUNJDC5otC7NPR1qXHvLMuAs5faE4DPEt"), derive(solana_frozen_abi_macro::AbiExample) )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -64,8 +64,8 @@ impl VoteState1_14_11 { } } -impl From for VoteState1_14_11 { - fn from(vote_state: VoteState) -> Self { +impl From for VoteState1_14_11 { + fn from(vote_state: VoteStateV3) -> Self { Self { node_pubkey: vote_state.node_pubkey, authorized_withdrawer: vote_state.authorized_withdrawer, @@ -96,7 +96,7 @@ mod tests { let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap(); let mut test_vote_state = MaybeUninit::uninit(); - VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); + VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); let test_vote_state = unsafe { test_vote_state.assume_init() }; assert_eq!( @@ -119,7 +119,7 @@ mod tests { let target_vote_state = target_vote_state_versions.convert_to_current(); let mut test_vote_state = MaybeUninit::uninit(); - VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); + VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap(); let test_vote_state = unsafe { test_vote_state.assume_init() }; assert_eq!(target_vote_state, test_vote_state); diff --git a/vote-interface/src/state/vote_state_v3.rs b/vote-interface/src/state/vote_state_v3.rs index c12ee6a24..3ba8b26b6 100644 --- a/vote-interface/src/state/vote_state_v3.rs +++ b/vote-interface/src/state/vote_state_v3.rs @@ -15,7 +15,7 @@ use { authorized_voters::AuthorizedVoters, error::VoteError, state::DEFAULT_PRIOR_VOTERS_OFFSET, }, solana_clock::{Clock, Epoch, Slot, UnixTimestamp}, - solana_instruction::error::InstructionError, + solana_instruction_error::InstructionError, solana_pubkey::Pubkey, solana_rent::Rent, std::{collections::VecDeque, fmt::Debug}, @@ -23,13 +23,13 @@ use { #[cfg_attr( feature = "frozen-abi", - frozen_abi(digest = "BRwozbypfYXsHqFVj9w3iH5x1ak2NWHqCCn6pr3gHBkG"), + frozen_abi(digest = "pZqasQc6duzMYzpzU7eriHH9cMXmubuUP4NmCrkWZjt"), derive(AbiExample) )] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Debug, Default, PartialEq, Eq, Clone)] #[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))] -pub struct VoteState { +pub struct VoteStateV3 { /// the node that votes in this account pub node_pubkey: Pubkey, @@ -61,14 +61,14 @@ pub struct VoteState { pub last_timestamp: BlockTimestamp, } -impl VoteState { +impl VoteStateV3 { pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self { Self { node_pubkey: vote_init.node_pubkey, authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter), authorized_withdrawer: vote_init.authorized_withdrawer, commission: vote_init.commission, - ..VoteState::default() + ..VoteStateV3::default() } } @@ -86,7 +86,7 @@ impl VoteState { node_pubkey, root_slot: Some(root_slot), votes, - ..VoteState::default() + ..VoteStateV3::default() } } @@ -103,7 +103,7 @@ impl VoteState { } pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 { - rent.minimum_balance(VoteState::size_of()) + rent.minimum_balance(VoteStateV3::size_of()) } /// Upper limit on the size of the Vote State @@ -113,7 +113,7 @@ impl VoteState { } // NOTE we retain `bincode::deserialize` for `not(target_os = "solana")` pending testing on mainnet-beta - // once that testing is done, `VoteState::deserialize_into` may be used for all targets + // once that testing is done, `VoteStateV3::deserialize_into` may be used for all targets // conversion of V0_23_5 to current must be handled specially, however // because it inserts a null voter into `authorized_voters` // which `VoteStateVersions::is_uninitialized` erroneously reports as initialized @@ -133,23 +133,23 @@ impl VoteState { } } - /// Deserializes the input `VoteStateVersions` buffer directly into the provided `VoteState`. + /// Deserializes the input `VoteStateVersions` buffer directly into the provided `VoteStateV3`. /// /// In a SBPF context, V0_23_5 is not supported, but in non-SBPF, all versions are supported for /// compatibility with `bincode::deserialize`. /// /// On success, `vote_state` reflects the state of the input data. On failure, `vote_state` is - /// reset to `VoteState::default()`. + /// reset to `VoteStateV3::default()`. #[cfg(any(target_os = "solana", feature = "bincode"))] pub fn deserialize_into( input: &[u8], - vote_state: &mut VoteState, + vote_state: &mut VoteStateV3, ) -> Result<(), InstructionError> { - // Rebind vote_state to *mut VoteState so that the &mut binding isn't + // Rebind vote_state to *mut VoteStateV3 so that the &mut binding isn't // accessible anymore, preventing accidental use after this point. // // NOTE: switch to ptr::from_mut() once platform-tools moves to rustc >= 1.76 - let vote_state = vote_state as *mut VoteState; + let vote_state = vote_state as *mut VoteStateV3; // Safety: vote_state is valid to_drop (see drop_in_place() docs). After // dropping, the pointer is treated as uninitialized and only accessed @@ -158,9 +158,9 @@ impl VoteState { std::ptr::drop_in_place(vote_state); } - // This is to reset vote_state to VoteState::default() if deserialize fails or panics. + // This is to reset vote_state to VoteStateV3::default() if deserialize fails or panics. struct DropGuard { - vote_state: *mut VoteState, + vote_state: *mut VoteStateV3, } impl Drop for DropGuard { @@ -169,20 +169,20 @@ impl VoteState { // // Deserialize failed or panicked so at this point vote_state is uninitialized. We // must write a new _valid_ value into it or after returning (or unwinding) from - // this function the caller is left with an uninitialized `&mut VoteState`, which is + // this function the caller is left with an uninitialized `&mut VoteStateV3`, which is // UB (references must always be valid). // // This is always safe and doesn't leak memory because deserialize_into_ptr() writes // into the fields that heap alloc only when it returns Ok(). unsafe { - self.vote_state.write(VoteState::default()); + self.vote_state.write(VoteStateV3::default()); } } } let guard = DropGuard { vote_state }; - let res = VoteState::deserialize_into_ptr(input, vote_state); + let res = VoteStateV3::deserialize_into_ptr(input, vote_state); if res.is_ok() { std::mem::forget(guard); } @@ -191,26 +191,28 @@ impl VoteState { } /// Deserializes the input `VoteStateVersions` buffer directly into the provided - /// `MaybeUninit`. + /// `MaybeUninit`. /// /// In a SBPF context, V0_23_5 is not supported, but in non-SBPF, all versions are supported for /// compatibility with `bincode::deserialize`. /// - /// On success, `vote_state` is fully initialized and can be converted to `VoteState` using - /// [MaybeUninit::assume_init]. On failure, `vote_state` may still be uninitialized and must not - /// be converted to `VoteState`. + /// On success, `vote_state` is fully initialized and can be converted to + /// `VoteStateV3` using + /// [`MaybeUninit::assume_init`](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init). + /// On failure, `vote_state` may still be uninitialized and must not be + /// converted to `VoteStateV3`. #[cfg(any(target_os = "solana", feature = "bincode"))] pub fn deserialize_into_uninit( input: &[u8], - vote_state: &mut std::mem::MaybeUninit, + vote_state: &mut std::mem::MaybeUninit, ) -> Result<(), InstructionError> { - VoteState::deserialize_into_ptr(input, vote_state.as_mut_ptr()) + VoteStateV3::deserialize_into_ptr(input, vote_state.as_mut_ptr()) } #[cfg(any(target_os = "solana", feature = "bincode"))] fn deserialize_into_ptr( input: &[u8], - vote_state: *mut VoteState, + vote_state: *mut VoteStateV3, ) -> Result<(), InstructionError> { use vote_state_deserialize::deserialize_vote_state_into; @@ -223,8 +225,8 @@ impl VoteState { 0 => { #[cfg(not(target_os = "solana"))] { - // Safety: vote_state is valid as it comes from `&mut MaybeUninit` or - // `&mut VoteState`. In the first case, the value is uninitialized so we write() + // Safety: vote_state is valid as it comes from `&mut MaybeUninit` or + // `&mut VoteStateV3`. In the first case, the value is uninitialized so we write() // to avoid dropping invalid data; in the latter case, we `drop_in_place()` // before writing so the value has already been dropped and we just write a new // one in place. @@ -261,40 +263,6 @@ impl VoteState { }) } - /// returns commission split as (voter_portion, staker_portion, was_split) tuple - /// - /// if commission calculation is 100% one way or other, - /// indicate with false for was_split - #[deprecated(since = "2.2.0", note = "logic was moved into the agave runtime crate")] - pub fn commission_split(&self, on: u64) -> (u64, u64, bool) { - match self.commission.min(100) { - 0 => (0, on, false), - 100 => (on, 0, false), - split => { - let on = u128::from(on); - // Calculate mine and theirs independently and symmetrically instead of - // using the remainder of the other to treat them strictly equally. - // This is also to cancel the rewarding if either of the parties - // should receive only fractional lamports, resulting in not being rewarded at all. - // Thus, note that we intentionally discard any residual fractional lamports. - let mine = on - .checked_mul(u128::from(split)) - .expect("multiplication of a u64 and u8 should not overflow") - / 100u128; - let theirs = on - .checked_mul(u128::from( - 100u8 - .checked_sub(split) - .expect("commission cannot be greater than 100"), - )) - .expect("multiplication of a u64 and u8 should not overflow") - / 100u128; - - (mine as u64, theirs as u64, true) - } - } - } - /// Returns if the vote state contains a slot `candidate_slot` pub fn contains_slot(&self, candidate_slot: Slot) -> bool { self.votes @@ -303,14 +271,14 @@ impl VoteState { } #[cfg(test)] - pub(crate) fn get_max_sized_vote_state() -> VoteState { + pub(crate) fn get_max_sized_vote_state() -> VoteStateV3 { use solana_epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET; let mut authorized_voters = AuthorizedVoters::default(); for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET { authorized_voters.insert(i, Pubkey::new_unique()); } - VoteState { + VoteStateV3 { votes: VecDeque::from(vec![LandedVote::default(); MAX_LOCKOUT_HISTORY]), root_slot: Some(u64::MAX), epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY], @@ -454,7 +422,7 @@ impl VoteState { } /// Number of "credits" owed to this account from the mining pool. Submit this - /// VoteState to the Rewards program to trade credits for lamports. + /// VoteStateV3 to the Rewards program to trade credits for lamports. pub fn credits(&self) -> u64 { if self.epoch_credits.is_empty() { 0 @@ -592,7 +560,7 @@ impl VoteState { pub fn is_correct_size_and_initialized(data: &[u8]) -> bool { const VERSION_OFFSET: usize = 4; const DEFAULT_PRIOR_VOTERS_END: usize = VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET; - data.len() == VoteState::size_of() + data.len() == VoteStateV3::size_of() && data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET] } } @@ -603,12 +571,12 @@ mod vote_state_deserialize { crate::{ authorized_voters::AuthorizedVoters, state::{ - BlockTimestamp, LandedVote, Lockout, VoteState, MAX_EPOCH_CREDITS_HISTORY, + BlockTimestamp, LandedVote, Lockout, VoteStateV3, MAX_EPOCH_CREDITS_HISTORY, MAX_ITEMS, MAX_LOCKOUT_HISTORY, }, }, solana_clock::Epoch, - solana_instruction::error::InstructionError, + solana_instruction_error::InstructionError, solana_pubkey::Pubkey, solana_serialize_utils::cursor::{ read_bool, read_i64, read_option_u64, read_pubkey, read_pubkey_into, read_u32, @@ -619,7 +587,7 @@ mod vote_state_deserialize { pub(super) fn deserialize_vote_state_into( cursor: &mut Cursor<&[u8]>, - vote_state: *mut VoteState, + vote_state: *mut VoteStateV3, has_latency: bool, ) -> Result<(), InstructionError> { // General safety note: we must use add_or_mut! to access the `vote_state` fields as the value @@ -648,7 +616,7 @@ mod vote_state_deserialize { // valid pointers. // // Heap allocated collections - votes, authorized_voters and epoch_credits - - // are guaranteed not to leak after this point as the VoteState is fully + // are guaranteed not to leak after this point as the VoteStateV3 is fully // initialized and will be regularly dropped. unsafe { addr_of_mut!((*vote_state).commission).write(commission); @@ -698,7 +666,7 @@ mod vote_state_deserialize { fn read_prior_voters_into>( cursor: &mut Cursor, - vote_state: *mut VoteState, + vote_state: *mut VoteStateV3, ) -> Result<(), InstructionError> { // Safety: if vote_state is non-null, prior_voters is guaranteed to be valid too unsafe { @@ -740,7 +708,7 @@ mod vote_state_deserialize { fn read_last_timestamp_into>( cursor: &mut Cursor, - vote_state: *mut VoteState, + vote_state: *mut VoteStateV3, ) -> Result<(), InstructionError> { let slot = read_u64(cursor)?; let timestamp = read_i64(cursor)?; diff --git a/vote-interface/src/state/vote_state_versions.rs b/vote-interface/src/state/vote_state_versions.rs index 74afac088..8ffde1065 100644 --- a/vote-interface/src/state/vote_state_versions.rs +++ b/vote-interface/src/state/vote_state_versions.rs @@ -5,7 +5,7 @@ use { authorized_voters::AuthorizedVoters, state::{ vote_state_0_23_5::VoteState0_23_5, vote_state_1_14_11::VoteState1_14_11, CircBuf, - LandedVote, Lockout, VoteState, + LandedVote, Lockout, VoteStateV3, }, }, solana_pubkey::Pubkey, @@ -20,21 +20,21 @@ use { pub enum VoteStateVersions { V0_23_5(Box), V1_14_11(Box), - Current(Box), + Current(Box), } impl VoteStateVersions { - pub fn new_current(vote_state: VoteState) -> Self { + pub fn new_current(vote_state: VoteStateV3) -> Self { Self::Current(Box::new(vote_state)) } - pub fn convert_to_current(self) -> VoteState { + pub fn convert_to_current(self) -> VoteStateV3 { match self { VoteStateVersions::V0_23_5(state) => { let authorized_voters = AuthorizedVoters::new(state.authorized_voter_epoch, state.authorized_voter); - VoteState { + VoteStateV3 { node_pubkey: state.node_pubkey, authorized_withdrawer: state.authorized_withdrawer, @@ -55,7 +55,7 @@ impl VoteStateVersions { } } - VoteStateVersions::V1_14_11(state) => VoteState { + VoteStateVersions::V1_14_11(state) => VoteStateV3 { node_pubkey: state.node_pubkey, authorized_withdrawer: state.authorized_withdrawer, commission: state.commission, @@ -95,14 +95,14 @@ impl VoteStateVersions { pub fn vote_state_size_of(is_current: bool) -> usize { if is_current { - VoteState::size_of() + VoteStateV3::size_of() } else { VoteState1_14_11::size_of() } } pub fn is_correct_size_and_initialized(data: &[u8]) -> bool { - VoteState::is_correct_size_and_initialized(data) + VoteStateV3::is_correct_size_and_initialized(data) || VoteState1_14_11::is_correct_size_and_initialized(data) } } @@ -112,7 +112,7 @@ impl Arbitrary<'_> for VoteStateVersions { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { let variant = u.choose_index(2)?; match variant { - 0 => Ok(Self::Current(Box::new(VoteState::arbitrary(u)?))), + 0 => Ok(Self::Current(Box::new(VoteStateV3::arbitrary(u)?))), 1 => Ok(Self::V1_14_11(Box::new(VoteState1_14_11::arbitrary(u)?))), _ => unreachable!(), }