diff --git a/Cargo.lock b/Cargo.lock index c20e26f..5a6cdc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,18 +13,45 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -52,6 +79,19 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -70,6 +110,26 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -85,6 +145,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -107,6 +176,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "cpufeatures" version = "0.2.11" @@ -116,6 +191,18 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -149,6 +236,31 @@ dependencies = [ "subtle", ] +[[package]] +name = "either" +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", + "hkdf", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "errno" version = "0.3.7" @@ -165,12 +277,28 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + [[package]] name = "generic-array" version = "0.14.7" @@ -179,6 +307,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -192,12 +321,38 @@ dependencies = [ "wasi", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hex-literal" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -217,6 +372,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "keccak" version = "0.1.4" @@ -228,9 +392,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ "spin", ] @@ -253,6 +417,16 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -273,11 +447,10 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] @@ -294,14 +467,132 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "p3-baby-bear" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7521838ecab2ddf4f7bc4ceebad06ec02414729598485c1ada516c39900820e8" +dependencies = [ + "num-bigint", + "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "rand", + "serde", +] + +[[package]] +name = "p3-dft" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46414daedd796f1eefcdc1811c0484e4bced5729486b6eaba9521c572c76761a" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-field" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48948a0516b349e9d1cdb95e7236a6ee010c44e68c5cc78b4b92bf1c4022a0d9" +dependencies = [ + "itertools", + "num-bigint", + "num-traits", + "p3-util", + "rand", + "serde", +] + +[[package]] +name = "p3-matrix" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4de3f373589477cb735ea58e125898ed20935e03664b4614c7fac258b3c42f" +dependencies = [ + "itertools", + "p3-field", + "p3-maybe-rayon", + "p3-util", + "rand", + "serde", + "tracing", +] + +[[package]] +name = "p3-maybe-rayon" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3968ad1160310296eb04f91a5f4edfa38fe1d6b2b8cd6b5c64e6f9b7370979e" + +[[package]] +name = "p3-mds" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2356b1ed0add6d5dfbf7a338ce534a6fde827374394a52cec16a0840af6e97c9" +dependencies = [ + "itertools", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-symmetric", + "p3-util", + "rand", +] + +[[package]] +name = "p3-poseidon2" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da1eec7e1b6900581bedd95e76e1ef4975608dd55be9872c9d257a8a9651c3a" +dependencies = [ + "gcd", + "p3-field", + "p3-mds", + "p3-symmetric", + "rand", + "serde", +] + +[[package]] +name = "p3-symmetric" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb439bea1d822623b41ff4b51e3309e80d13cadf8b86d16ffd5e6efb9fdc360" +dependencies = [ + "itertools", + "p3-field", + "serde", +] + +[[package]] +name = "p3-util" +version = "0.2.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c2c2010678b9332b563eaa38364915b585c1a94b5ca61e2c7541c087ddda5c" +dependencies = [ + "serde", +] + [[package]] name = "pbkdf2" version = "0.12.2" @@ -321,6 +612,12 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "pkcs1" version = "0.7.5" @@ -367,9 +664,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -402,9 +699,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -468,7 +765,10 @@ name = "rsa" version = "0.9.6" dependencies = [ "base64ct", + "bytemuck", + "cfg-if", "const-oid", + "crypto-bigint", "digest", "hex-literal", "num-bigint-dig", @@ -487,6 +787,7 @@ dependencies = [ "sha2", "sha3", "signature", + "sp1-lib", "spki", "subtle", "zeroize", @@ -537,20 +838,33 @@ dependencies = [ "sha2", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + [[package]] name = "serde" -version = "1.0.192" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -598,6 +912,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -614,11 +934,43 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +[[package]] +name = "sp1-lib" +version = "5.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0fd8bc101e5603ccf2dc1836ea06410f25ce2298755b2dac626add9be2424b4" +dependencies = [ + "bincode", + "elliptic-curve", + "serde", + "sp1-primitives", +] + +[[package]] +name = "sp1-primitives" +version = "5.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "699935774a5131c1a8b371108d0666c0c80c43611045fb77fae43f2f242676d5" +dependencies = [ + "bincode", + "blake3", + "cfg-if", + "hex", + "lazy_static", + "num-bigint", + "p3-baby-bear", + "p3-field", + "p3-poseidon2", + "p3-symmetric", + "serde", + "sha2", +] + [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" @@ -638,9 +990,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -660,6 +1012,37 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + [[package]] name = "typenum" version = "1.17.0" diff --git a/Cargo.toml b/Cargo.toml index e4b2265..779edc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,23 +13,51 @@ readme = "README.md" rust-version = "1.65" [dependencies] -num-bigint = { version = "0.8.2", features = ["i128", "prime", "zeroize"], default-features = false, package = "num-bigint-dig" } -num-traits = { version= "0.2.9", default-features = false, features = ["libm"] } +num-bigint = { version = "0.8.2", features = [ + "i128", + "prime", + "zeroize", +], default-features = false, package = "num-bigint-dig" } +num-traits = { version = "0.2.9", default-features = false, features = [ + "libm", +] } num-integer = { version = "0.1.39", default-features = false } rand_core = { version = "0.6.4", default-features = false } const-oid = { version = "0.9", default-features = false } subtle = { version = "2.1.1", default-features = false } -digest = { version = "0.10.5", default-features = false, features = ["alloc", "oid"] } -pkcs1 = { version = "0.7.5", default-features = false, features = ["alloc", "pkcs8"] } +digest = { version = "0.10.5", default-features = false, features = [ + "alloc", + "oid", +] } +pkcs1 = { version = "0.7.5", default-features = false, features = [ + "alloc", + "pkcs8", +] } pkcs8 = { version = "0.10.2", default-features = false, features = ["alloc"] } -signature = { version = ">2.0, <2.3", default-features = false , features = ["alloc", "digest", "rand_core"] } +signature = { version = ">2.0, <2.3", default-features = false, features = [ + "alloc", + "digest", + "rand_core", +] } spki = { version = "0.7.3", default-features = false, features = ["alloc"] } zeroize = { version = "1.5", features = ["alloc"] } +crypto-bigint = "0.5.5" +cfg-if = "1.0.0" +bytemuck = { version = "1.16.1", features = ["derive"] } # optional dependencies -sha1 = { version = "0.10.5", optional = true, default-features = false, features = ["oid"] } -sha2 = { version = "0.10.6", optional = true, default-features = false, features = ["oid"] } -serde = { version = "1.0.184", optional = true, default-features = false, features = ["derive"] } +sha1 = { version = "0.10.5", optional = true, default-features = false, features = [ + "oid", +] } +sha2 = { version = "0.10.6", optional = true, default-features = false, features = [ + "oid", +] } +serde = { version = "1.0.184", optional = true, default-features = false, features = [ + "derive", +] } + +[target.'cfg(all(target_os = "zkvm", target_vendor = "succinct"))'.dependencies] +sp1-lib = "6.2.0" [dev-dependencies] base64ct = { version = "1", features = ["alloc"] } diff --git a/src/algorithms/rsa.rs b/src/algorithms/rsa.rs index 3510152..3fe4a31 100644 --- a/src/algorithms/rsa.rs +++ b/src/algorithms/rsa.rs @@ -8,9 +8,31 @@ use num_traits::{FromPrimitive, One, Pow, Signed, Zero}; use rand_core::CryptoRngCore; use zeroize::{Zeroize, Zeroizing}; +#[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] +use bytemuck::cast_ref; +#[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] +use core::convert::TryInto; +#[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] +use crypto_bigint::{Encoding, Integer as CryptoInteger, NonZero, U2048, U256, U3072, U4096, U6144, U8192}; +#[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] +use sp1_lib::io::hint_slice; + use crate::errors::{Error, Result}; use crate::traits::{PrivateKeyParts, PublicKeyParts}; +// Architecture-specific type definitions +#[cfg(target_pointer_width = "32")] +type ChunkWord = u32; +#[cfg(target_pointer_width = "64")] +type ChunkWord = u64; + +#[cfg(target_pointer_width = "32")] +const CHUNK_SIZE: usize = 8; +#[cfg(target_pointer_width = "64")] +const CHUNK_SIZE: usize = 4; + +type Chunk = [ChunkWord; CHUNK_SIZE]; + /// ⚠️ Raw RSA encryption of m with the public key. No padding is performed. /// /// # ☢️️ WARNING: HAZARDOUS API ☢️ @@ -19,9 +41,353 @@ use crate::traits::{PrivateKeyParts, PublicKeyParts}; /// or signature scheme. See the [module-level documentation][crate::hazmat] for more information. #[inline] pub fn rsa_encrypt(key: &K, m: &BigUint) -> Result { + #[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] + { + match key.size() { + 256 => { + use zkvm::*; + let m_chunks = zkvm::from_biguint_to_chunks::<8>(m); + let e_chunks = zkvm::from_biguint_to_chunks::<8>(key.e()); + let n_chunks = zkvm::from_biguint_to_chunks::<8>(key.n()); + let result = zkvm::custom_modpow_2048(&m_chunks, &e_chunks, &n_chunks); + return Ok(result); + }, + 384 => { + use zkvm::*; + let m_chunks = zkvm::from_biguint_to_chunks::<12>(m); + let e_chunks = zkvm::from_biguint_to_chunks::<12>(key.e()); + let n_chunks = zkvm::from_biguint_to_chunks::<12>(key.n()); + let result = zkvm::custom_modpow_3072(&m_chunks, &e_chunks, &n_chunks); + return Ok(result); + }, + 512 => { + use zkvm::*; + let m_chunks = zkvm::from_biguint_to_chunks::<16>(m); + let e_chunks = zkvm::from_biguint_to_chunks::<16>(key.e()); + let n_chunks = zkvm::from_biguint_to_chunks::<16>(key.n()); + let result = zkvm::custom_modpow_4096(&m_chunks, &e_chunks, &n_chunks); + return Ok(result); + }, + _ => { + // Fall through to standard modpow for unsupported sizes + } + } + } Ok(m.modpow(key.e(), key.n())) } +/// # ☢️️ WARNING: HAZARDOUS API ☢️ +/// +/// All inputs are ASSUMED to be on the range of [0, 2^4096).] +/// +/// Attempting to use this function with values outside of this range will result in truncation, +/// and may have unintended side effects! +#[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] +mod zkvm { + use super::*; + + // Macro to generate mul_mod functions for different bit sizes + macro_rules! impl_mul_mod { + ($name:ident, $chunks:expr, $bytes:expr, $fd_type:expr) => { + fn $name( + a_chunks: &[Chunk; $chunks], + b_chunks: &[Chunk; $chunks], + modulus_chunks: &[Chunk; $chunks] + ) -> [Chunk; $chunks] { + let prod_chunks = mul_generic_chunks::<$chunks, {$chunks * 2}>(a_chunks, b_chunks); + + // Convert to bytes for SP1 I/O using direct transmute + let prod_bytes: [u8; $bytes * 2] = unsafe { + core::mem::transmute::<[Chunk; $chunks * 2], [u8; $bytes * 2]>(prod_chunks) + }; + let modulus_bytes: [u8; $bytes] = unsafe { + core::mem::transmute::<[Chunk; $chunks], [u8; $bytes]>(*modulus_chunks) + }; + + // Call the hook to perform the modmul operation in the executor + sp1_lib::io::write( + $fd_type, + &prod_bytes.into_iter().chain(modulus_bytes.into_iter()).collect::>(), + ); + + let result_bytes: [u8; $bytes] = match sp1_lib::io::read_vec().try_into() { + Ok(b) => b, + Err(_) => sp1_lib::invalid_hint!( + "RSA modmul: result hint is not {} bytes", + $bytes + ), + }; + let quotient_bytes: [u8; $bytes] = match sp1_lib::io::read_vec().try_into() { + Ok(b) => b, + Err(_) => sp1_lib::invalid_hint!( + "RSA modmul: quotient hint is not {} bytes", + $bytes + ), + }; + + // Convert back to chunks + let result_chunks: [Chunk; $chunks] = unsafe { + core::mem::transmute::<[u8; $bytes], [Chunk; $chunks]>(result_bytes) + }; + let quotient_chunks: [Chunk; $chunks] = unsafe { + core::mem::transmute::<[u8; $bytes], [Chunk; $chunks]>(quotient_bytes) + }; + + // Verify: prod == quotient * modulus + result and 0 <= result < modulus. + let quotient_mul_chunks = mul_generic_chunks::<$chunks, {$chunks * 2}>("ient_chunks, modulus_chunks); + + let mut verification_prod = quotient_mul_chunks; + add_generic_chunks(&mut verification_prod, &result_chunks); + + for i in 0..($chunks * 2) { + for j in 0..CHUNK_SIZE { + if prod_chunks[i][j] != verification_prod[i][j] { + sp1_lib::invalid_hint!( + "RSA modmul: prod != quotient * modulus + result" + ); + } + } + } + + assert_less_than::<$chunks>(&result_chunks, modulus_chunks); + + result_chunks + } + }; + } + + // Generate the three mul_mod functions + impl_mul_mod!(mul_mod_2048, 8, 256, sp1_lib::io::FD_RSA_MUL_MOD); + impl_mul_mod!(mul_mod_3072, 12, 384, sp1_lib::io::FD_RSA_MUL_MOD); + impl_mul_mod!(mul_mod_4096, 16, 512, sp1_lib::io::FD_RSA_MUL_MOD); + + // Macro to generate modpow functions + macro_rules! impl_modpow { + ($name:ident, $chunks:expr, $bigint_type:ty, $mul_mod_fn:ident) => { + pub(super) fn $name( + base_chunks: &[Chunk; $chunks], + exp_chunks: &[Chunk; $chunks], + modulus_chunks: &[Chunk; $chunks] + ) -> BigUint { + // Convert chunks to crypto_bigint type for easier manipulation + let exp_bytes = chunks_to_bytes::<$chunks>(exp_chunks); + let exp_bigint = <$bigint_type>::from_le_slice(&exp_bytes); + + assert!(!chunks_is_zero::<$chunks>(modulus_chunks), "modulo cannot be zero"); + + let result_chunks = if exp_bigint == <$bigint_type>::from_u64(65537u64) { + // Optimized path for e = 65537 + let one_chunks = chunks_one::<$chunks>(); + let mut result_chunks = $mul_mod_fn(base_chunks, &one_chunks, modulus_chunks); + let base_reduced = result_chunks; + + // Square 16 times + for _ in 0..16 { + result_chunks = $mul_mod_fn(&result_chunks, &result_chunks, modulus_chunks); + } + + $mul_mod_fn(&result_chunks, &base_reduced, modulus_chunks) + } else { + // Square-and-multiply + let one_chunks = chunks_one::<$chunks>(); + let mut result_chunks = one_chunks; + let mut base_chunks = $mul_mod_fn(base_chunks, &one_chunks, modulus_chunks); + let mut exp = exp_bigint; + + while exp > <$bigint_type>::ZERO { + if exp.is_odd().into() { + result_chunks = $mul_mod_fn(&result_chunks, &base_chunks, modulus_chunks); + } + exp = exp.shr(1); + base_chunks = $mul_mod_fn(&base_chunks, &base_chunks, modulus_chunks); + } + + result_chunks + }; + + BigUint::from_bytes_le(&chunks_to_bytes::<$chunks>(&result_chunks)) + } + }; + } + + // Generate the three modpow functions + impl_modpow!(custom_modpow_2048, 8, U2048, mul_mod_2048); + impl_modpow!(custom_modpow_3072, 12, U3072, mul_mod_3072); + impl_modpow!(custom_modpow_4096, 16, U4096, mul_mod_4096); + + /// Generic multiplication using schoolbook algorithm with 256-bit chunks + /// Returns a vector of 256-bit chunks representing the full product + fn mul_generic_chunks(a_chunks: &[Chunk; N], b_chunks: &[Chunk; N]) -> [Chunk; N2] { + let mut out = [chunk_zero(); N2]; + + let mut lo = chunk_zero(); + let mut hi = chunk_zero(); + let mut tmp_hi = chunk_zero(); + let zero_carry = chunk_zero(); + + for i in 0..N { + for j in 0..N { + let k = i + j; + + unsafe { + sp1_lib::syscall_uint256_mul_with_carry( + a_chunks[i].as_ptr() as *const Chunk, + b_chunks[j].as_ptr() as *const Chunk, + zero_carry.as_ptr() as *const Chunk, + lo.as_mut_ptr() as *mut Chunk, + hi.as_mut_ptr() as *mut Chunk, + ); + } + + unsafe { + sp1_lib::syscall_uint256_add_with_carry( + out[k].as_ptr() as *const Chunk, + lo.as_ptr() as *const Chunk, + zero_carry.as_ptr() as *const Chunk, + out[k].as_mut_ptr() as *mut Chunk, + tmp_hi.as_mut_ptr() as *mut Chunk, + ); + } + + unsafe { + sp1_lib::syscall_uint256_add_with_carry( + out[k + 1].as_ptr() as *const Chunk, + hi.as_ptr() as *const Chunk, + tmp_hi.as_ptr() as *const Chunk, + out[k + 1].as_mut_ptr() as *mut Chunk, + tmp_hi.as_mut_ptr() as *mut Chunk, + ); + } + + let mut idx = k + 2; + while tmp_hi[0] != 0 && idx < N2 { + unsafe { + sp1_lib::syscall_uint256_add_with_carry( + out[idx].as_ptr() as *const Chunk, + zero_carry.as_ptr() as *const Chunk, + tmp_hi.as_ptr() as *const Chunk, + out[idx].as_mut_ptr() as *mut Chunk, + tmp_hi.as_mut_ptr() as *mut Chunk, + ); + } + idx += 1; + } + } + } + + out + } + + /// Generic addition of two chunk arrays with different sizes + /// Adds smaller array to the lower part of larger array, handling carries + fn add_generic_chunks(larger: &mut [Chunk], smaller: &[Chunk]) { + let mut carry = chunk_zero(); + let zero_carry = chunk_zero(); + + for i in 0..smaller.len() { + unsafe { + sp1_lib::syscall_uint256_add_with_carry( + larger[i].as_ptr() as *const Chunk, + smaller[i].as_ptr() as *const Chunk, + carry.as_ptr() as *const Chunk, + larger[i].as_mut_ptr() as *mut Chunk, + carry.as_mut_ptr() as *mut Chunk, + ); + } + } + + let mut idx = smaller.len(); + while idx < larger.len() && carry[0] != 0 { + unsafe { + sp1_lib::syscall_uint256_add_with_carry( + larger[idx].as_ptr() as *const Chunk, + zero_carry.as_ptr() as *const Chunk, + carry.as_ptr() as *const Chunk, + larger[idx].as_mut_ptr() as *mut Chunk, + carry.as_mut_ptr() as *mut Chunk, + ); + } + idx += 1; + } + } + + /// Verify that the hinted result is less than the modulus. + /// Halts the zkVM with exit code 3 on failure (invalid hint). + fn assert_less_than(result_chunk: &[Chunk; N], modulus_chunk: &[Chunk; N]) { + for i in (0..N).rev() { + for j in (0..CHUNK_SIZE).rev() { + if result_chunk[i][j] < modulus_chunk[i][j] { + return; + } + if result_chunk[i][j] != modulus_chunk[i][j] { + sp1_lib::invalid_hint!("RSA modmul: result >= modulus"); + } + } + } + sp1_lib::invalid_hint!("RSA modmul: result == modulus"); + } + + /// Generic helper to convert bytes to chunks + fn bytes_to_chunks(bytes: &[u8]) -> [Chunk; N] { + let mut chunks = [chunk_zero(); N]; + let word_size = core::mem::size_of::(); + assert!(bytes.len() == 32 * N, "incorrect length"); + for (i, chunk) in chunks.iter_mut().enumerate() { + for (j, word) in chunk.iter_mut().enumerate() { + let byte_idx = (i * CHUNK_SIZE + j) * word_size; + let word_bytes = &bytes[byte_idx..byte_idx + word_size]; + *word = ChunkWord::from_le_bytes(word_bytes.try_into().unwrap()); + } + } + chunks + } + + /// Generic helper to convert chunks to bytes + fn chunks_to_bytes(chunks: &[Chunk; N]) -> Vec { + chunks.iter() + .flat_map(|chunk| chunk.iter().flat_map(|&word| word.to_le_bytes())) + .collect() + } + + /// Check if chunk array is zero + fn chunks_is_zero(chunks: &[Chunk; N]) -> bool { + for i in 0..N { + for j in 0..CHUNK_SIZE { + if chunks[i][j] != 0 { + return false; + } + } + } + true + } + + /// Get chunk array representing one + fn chunks_one() -> [Chunk; N] { + let mut chunks = [chunk_zero(); N]; + chunks[0][0] = 1; + chunks + } + + /// Helper to create zero chunk + fn chunk_zero() -> Chunk { + [ChunkWord::default(); CHUNK_SIZE] + } + + /// Convert BigUint to chunks for arbitrary key sizes + pub(super) fn from_biguint_to_chunks(value: &BigUint) -> [Chunk; N] { + let mut padded_bytes = vec![0u8; N * 32]; + let value_bytes = value.to_bytes_le(); + for (i, &byte) in value_bytes.iter().enumerate() { + if i >= padded_bytes.len() { + panic!("value larger than allowed size"); + } + padded_bytes[i] = byte; + } + bytes_to_chunks(&padded_bytes) + } + +} + /// ⚠️ Performs raw RSA decryption with no padding or error checking. /// /// Returns a plaintext `BigUint`. Performs RSA blinding if an `Rng` is passed.