diff --git a/README.md b/README.md index ef579cfe9..6d0d0c4e5 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ Code should be formatted using [`fourmolu`](https://github.com/fourmolu/fourmolu version `0.13.1.0` and using the config `fourmolu.yaml` found in the project root. The CI is setup to ensure the code follows this style. -To check the formatting locally run the following commnad from the project root: +To check the formatting locally run the following command from the project root: **On unix-like systems**: diff --git a/haskell-src/Concordium/Crypto/BlockSignature.hs b/haskell-src/Concordium/Crypto/BlockSignature.hs index b137de608..bf06a99e8 100644 --- a/haskell-src/Concordium/Crypto/BlockSignature.hs +++ b/haskell-src/Concordium/Crypto/BlockSignature.hs @@ -51,7 +51,7 @@ signatureLength :: Int signatureLength = Ed25519.signatureSize sign :: KeyPair -> ByteString -> Signature -sign KeyPair{..} = Signature . Ed25519.sign signKey verifyKey +sign KeyPair{..} = Signature . Ed25519.sign signKey verify :: VerifyKey -> ByteString -> Signature -> Bool verify vfKey bs (Signature s) = Ed25519.verify vfKey bs s diff --git a/haskell-src/Concordium/Crypto/Ed25519Signature.hs b/haskell-src/Concordium/Crypto/Ed25519Signature.hs index 104e9d969..47bb10a92 100644 --- a/haskell-src/Concordium/Crypto/Ed25519Signature.hs +++ b/haskell-src/Concordium/Crypto/Ed25519Signature.hs @@ -25,7 +25,7 @@ import System.IO.Unsafe foreign import ccall unsafe "eddsa_priv_key" genPrivateKey :: IO (Ptr SignKey) foreign import ccall unsafe "eddsa_pub_key" derivePublicFFI :: Ptr SignKey -> IO (Ptr VerifyKey) -foreign import ccall unsafe "eddsa_sign" signFFI :: Ptr Word8 -> Word32 -> Ptr SignKey -> Ptr VerifyKey -> Ptr Word8 -> IO () +foreign import ccall unsafe "eddsa_sign" signFFI :: Ptr Word8 -> Word32 -> Ptr SignKey -> Ptr Word8 -> IO () foreign import ccall unsafe "eddsa_verify" verifyFFI :: Ptr Word8 -> Word32 -> Ptr VerifyKey -> Ptr Word8 -> CSize -> IO Int32 foreign import ccall unsafe "&eddsa_public_free" freeVerifyKey :: FunPtr (Ptr VerifyKey -> IO ()) foreign import ccall unsafe "eddsa_public_to_bytes" toBytesVerifyKey :: Ptr VerifyKey -> Ptr CSize -> IO (Ptr Word8) @@ -122,15 +122,14 @@ newKeyPair = do let verifyKey = deriveVerifyKey signKey return (signKey, verifyKey) -sign :: SignKey -> VerifyKey -> ByteString -> BSS.ShortByteString -sign signKey verifyKey m = unsafePerformIO $ +sign :: SignKey -> ByteString -> BSS.ShortByteString +sign signKey m = unsafePerformIO $ withSignKey signKey $ \signKeyPtr -> - withVerifyKey verifyKey $ \verifyKeyPtr -> - BS.unsafeUseAsCStringLen m $ \(m', mlen) -> do - -- this use of unsafe is fine because the sign function - -- checks the length before dereferencing the data pointer - ((), s) <- withAllocatedShortByteString signatureSize $ signFFI (castPtr m') (fromIntegral mlen) signKeyPtr verifyKeyPtr - return s + BS.unsafeUseAsCStringLen m $ \(m', mlen) -> do + -- this use of unsafe is fine because the sign function + -- checks the length before dereferencing the data pointer + ((), s) <- withAllocatedShortByteString signatureSize $ signFFI (castPtr m') (fromIntegral mlen) signKeyPtr + return s verify :: VerifyKey -> ByteString -> BSS.ShortByteString -> Bool verify vf m sig = (BSS.length sig == signatureSize) && (suc > 0) diff --git a/haskell-src/Concordium/Crypto/SignatureScheme.hs b/haskell-src/Concordium/Crypto/SignatureScheme.hs index 680e77b2f..944d35cba 100644 --- a/haskell-src/Concordium/Crypto/SignatureScheme.hs +++ b/haskell-src/Concordium/Crypto/SignatureScheme.hs @@ -142,7 +142,7 @@ toScheme n | otherwise = Nothing sign :: KeyPair -> ByteString -> Signature -sign KeyPairEd25519{..} = Signature . Ed25519.sign signKey verifyKey +sign KeyPairEd25519{..} = Signature . Ed25519.sign signKey verify :: VerifyKey -> ByteString -> Signature -> Bool verify (VerifyKeyEd25519 vfKey) bs (Signature s) = Ed25519.verify vfKey bs s diff --git a/identity-provider-service/Cargo.lock b/identity-provider-service/Cargo.lock index 578f8b13a..7a7e63211 100644 --- a/identity-provider-service/Cargo.lock +++ b/identity-provider-service/Cargo.lock @@ -78,6 +78,124 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint 0.4.4", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint 0.4.4", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -144,6 +262,12 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" @@ -359,6 +483,11 @@ name = "concordium_base" version = "3.2.0" dependencies = [ "anyhow", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", "bs58", "byteorder", "chrono", @@ -368,8 +497,8 @@ dependencies = [ "derive_more", "ed25519-dalek", "either", - "ff", - "group", + "ff 0.13.0", + "group 0.2.0", "hex", "itertools", "leb128", @@ -378,9 +507,7 @@ dependencies = [ "num", "num-bigint 0.4.4", "num-traits", - "pairing", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", "rayon", "rust_decimal", "serde", @@ -402,6 +529,12 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "convert_case" version = "0.4.0" @@ -478,17 +611,34 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "group 0.13.0", + "platforms", + "rand_core 0.6.4", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "darling" version = "0.20.3" @@ -530,6 +680,16 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.8" @@ -539,6 +699,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -573,24 +744,26 @@ dependencies = [ [[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek", "ed25519", - "rand 0.7.3", + "rand_core 0.6.4", "serde", - "sha2 0.9.9", + "sha2 0.10.8", + "subtle", "zeroize", ] @@ -666,6 +839,17 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "ff_derive" version = "0.4.1" @@ -680,6 +864,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + [[package]] name = "fnv" version = "1.0.7" @@ -802,11 +992,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cbdfc48f95bef47e3daf3b9d552a1dde6311e3a5fefa43e16c59f651d56fe5b" dependencies = [ - "ff", + "ff 0.5.2", "rand 0.7.3", "rand_xorshift", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.3.21" @@ -1434,8 +1635,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94c40534479a28199cd5109da27fe2fc4a4728e4fc701d9e9c1bded78f3271e4" dependencies = [ "byteorder", - "ff", - "group", + "ff 0.5.2", + "group 0.2.0", "rand_core 0.5.1", ] @@ -1462,6 +1663,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "percent-encoding" version = "2.3.0" @@ -1500,12 +1707,28 @@ 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.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platforms" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2087,9 +2310,12 @@ 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 = [ + "rand_core 0.6.4", +] [[package]] name = "simdutf8" @@ -2138,6 +2364,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.8.0" @@ -2807,9 +3043,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] diff --git a/identity-provider-service/Cargo.toml b/identity-provider-service/Cargo.toml index 7af7483eb..ece0c7636 100644 --- a/identity-provider-service/Cargo.toml +++ b/identity-provider-service/Cargo.toml @@ -26,7 +26,7 @@ clap = "2.33" anyhow = "1.0" hex = "0.4" rust-embed = "6" -ed25519-dalek = "=1.0" +ed25519-dalek = "2.0" chrono = "0.4.24" # the patch version is necessary since chrono adds new functionality in patch versions sha2 = "0.10" diff --git a/identity-provider-service/src/bin/main.rs b/identity-provider-service/src/bin/main.rs index 2355c202c..d8ba21b11 100644 --- a/identity-provider-service/src/bin/main.rs +++ b/identity-provider-service/src/bin/main.rs @@ -15,7 +15,7 @@ use concordium_base::{ types::*, }, }; -use ed25519_dalek::{ExpandedSecretKey, PublicKey}; +use ed25519_dalek::{Signer, SigningKey}; use log::{error, info, warn}; use reqwest::Client; use serde_json::{from_str, json, to_value}; @@ -962,11 +962,8 @@ async fn save_validated_request( // Sign the id_cred_pub so that the identity verifier can verify that the given // id_cred_pub matches a valid identity creation request. - let public_key: PublicKey = server_config.ip_data.public_ip_info.ip_cdi_verify_key; - let expanded_secret_key: ExpandedSecretKey = - ExpandedSecretKey::from(&server_config.ip_data.ip_cdi_secret_key); - let signature_on_id_cred_pub = - expanded_secret_key.sign(id_cred_pub_hash.as_slice(), &public_key); + let expanded_secret_key = SigningKey::from(&server_config.ip_data.ip_cdi_secret_key); + let signature_on_id_cred_pub = expanded_secret_key.sign(id_cred_pub_hash.as_slice()); let serialized_signature = base16_encode_string(&signature_on_id_cred_pub); ok_or_500!( @@ -1000,11 +997,9 @@ async fn save_validated_request_v1( // Sign the id_cred_pub so that the identity verifier can verify that the given // id_cred_pub matches a valid identity creation request. - let public_key: PublicKey = server_config.ip_data.public_ip_info.ip_cdi_verify_key; - let expanded_secret_key: ExpandedSecretKey = - ExpandedSecretKey::from(&server_config.ip_data.ip_cdi_secret_key); - let signature_on_id_cred_pub = - expanded_secret_key.sign(id_cred_pub_hash.as_slice(), &public_key); + let expanded_secret_key: SigningKey = + SigningKey::from(&server_config.ip_data.ip_cdi_secret_key); + let signature_on_id_cred_pub = expanded_secret_key.sign(id_cred_pub_hash.as_slice()); let serialized_signature = base16_encode_string(&signature_on_id_cred_pub); ok_or_500!( diff --git a/idiss/Cargo.lock b/idiss/Cargo.lock index 756ac175e..be2e6a7e9 100644 --- a/idiss/Cargo.lock +++ b/idiss/Cargo.lock @@ -63,6 +63,124 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -92,6 +210,12 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bindgen" version = "0.56.0" @@ -321,7 +445,7 @@ dependencies = [ "fnv", "hashbrown 0.11.2", "hex", - "num-bigint 0.4.4", + "num-bigint", "num-integer", "num-traits", "rust_decimal", @@ -344,6 +468,11 @@ name = "concordium_base" version = "3.2.0" dependencies = [ "anyhow", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", "bs58", "byteorder", "chrono", @@ -353,19 +482,17 @@ dependencies = [ "derive_more", "ed25519-dalek", "either", - "ff", - "group", + "ff 0.13.0", + "group 0.2.0", "hex", "itertools", "leb128", "libc", "nom 7.1.3", "num", - "num-bigint 0.4.4", + "num-bigint", "num-traits", - "pairing", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", "rayon", "rust_decimal", "serde", @@ -387,6 +514,12 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "convert_case" version = "0.4.0" @@ -453,17 +586,34 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "group 0.13.0", + "platforms", + "rand_core 0.6.4", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "darling" version = "0.20.3" @@ -499,6 +649,16 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.8" @@ -508,6 +668,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -542,24 +713,26 @@ dependencies = [ [[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek", "ed25519", - "rand 0.7.3", + "rand_core 0.6.4", "serde", - "sha2 0.9.9", + "sha2 0.10.8", + "subtle", "zeroize", ] @@ -595,24 +768,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4530da57967e140ee0b44e0143aa66b5cb42bd9c503dbe316a15d5b0be65713e" dependencies = [ "byteorder", - "ff_derive", "rand_core 0.5.1", ] [[package]] -name = "ff_derive" -version = "0.4.1" +name = "ff" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5796e7d62ca01a00ed3a649b0da1ffa1ac8f06bcad40339df09dbdd69a05ba9" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "num-bigint 0.2.6", - "num-integer", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", + "bitvec", + "rand_core 0.6.4", + "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + [[package]] name = "fnv" version = "1.0.7" @@ -669,11 +844,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cbdfc48f95bef47e3daf3b9d552a1dde6311e3a5fefa43e16c59f651d56fe5b" dependencies = [ - "ff", + "ff 0.5.2", "rand 0.7.3", "rand_xorshift", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -763,11 +949,9 @@ dependencies = [ "chrono", "concordium_base", "ed25519-dalek", - "ff", "hex", "napi-build", "nodejs-sys", - "pairing", "serde", "serde_json", ] @@ -929,7 +1113,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ - "num-bigint 0.4.4", + "num-bigint", "num-complex", "num-integer", "num-iter", @@ -937,17 +1121,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.4" @@ -996,7 +1169,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint 0.4.4", + "num-bigint", "num-integer", "num-traits", ] @@ -1023,16 +1196,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -name = "pairing" -version = "0.15.1" +name = "paste" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94c40534479a28199cd5109da27fe2fc4a4728e4fc701d9e9c1bded78f3271e4" -dependencies = [ - "byteorder", - "ff", - "group", - "rand_core 0.5.1", -] +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "peeking_take_while" @@ -1040,6 +1207,22 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "platforms" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1422,9 +1605,12 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[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 = [ + "rand_core 0.6.4", +] [[package]] name = "simdutf8" @@ -1432,6 +1618,16 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.8.0" @@ -1787,9 +1983,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] diff --git a/idiss/Cargo.toml b/idiss/Cargo.toml index 185e8fabb..7507abedf 100644 --- a/idiss/Cargo.toml +++ b/idiss/Cargo.toml @@ -26,13 +26,11 @@ csharp = [] [dependencies] anyhow = "1.0" -pairing = "0.15" -ff = "0.5" hex = "0.4" serde = "1.0" serde_json = "1.0" chrono = "0.4.24" # the patch version is necessary since chrono adds new functionality in patch versions -ed25519-dalek = "1.0.1" +ed25519-dalek = "2.0" byteorder = "1.3" [dependencies.nodejs-sys] diff --git a/idiss/src/lib.rs b/idiss/src/lib.rs index 37a1a10ba..57051d529 100644 --- a/idiss/src/lib.rs +++ b/idiss/src/lib.rs @@ -4,7 +4,7 @@ use concordium_base::{ curve_arithmetic::*, id, id::{ - constants::{ArCurve, AttributeKind}, + constants::{ArCurve, AttributeKind, IpPairing}, identity_provider::{ create_initial_cdi, sign_identity_object, sign_identity_object_v1, validate_id_recovery_request, validate_request as ip_validate_request, @@ -14,11 +14,13 @@ use concordium_base::{ }, ps_sig, }; -use pairing::bls12_381::{Bls12, G1}; use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize}; #[cfg(feature = "nodejs")] use serde_json::ser::to_string; +type Bls12 = IpPairing; +type G1 = ArCurve; + type ExampleCurve = G1; type ExampleAttributeList = AttributeList<::ScalarField, AttributeKind>; diff --git a/mobile_wallet/Cargo.lock b/mobile_wallet/Cargo.lock index 2cb0c870f..6ddc5f595 100644 --- a/mobile_wallet/Cargo.lock +++ b/mobile_wallet/Cargo.lock @@ -15,13 +15,14 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -48,6 +49,124 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.6", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.6", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayvec" version = "0.7.2" @@ -78,6 +197,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" +[[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 = "block-buffer" version = "0.9.0" @@ -258,7 +389,7 @@ dependencies = [ "fnv", "hashbrown 0.11.2", "hex", - "num-bigint 0.4.3", + "num-bigint", "num-integer", "num-traits", "rust_decimal", @@ -281,6 +412,11 @@ name = "concordium_base" version = "3.2.0" dependencies = [ "anyhow", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", "bs58", "byteorder", "chrono", @@ -290,19 +426,17 @@ dependencies = [ "derive_more", "ed25519-dalek", "either", - "ff", - "group", + "ff 0.13.0", + "group 0.2.0", "hex", "itertools", "leb128", "libc", "nom", "num", - "num-bigint 0.4.3", + "num-bigint", "num-traits", - "pairing", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", "rayon", "rust_decimal", "serde", @@ -324,6 +458,12 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "convert_case" version = "0.4.0" @@ -400,17 +540,34 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.6", + "fiat-crypto", + "group 0.13.0", + "platforms", + "rand_core 0.6.4", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "cxx" version = "1.0.91" @@ -490,6 +647,27 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -525,24 +703,26 @@ dependencies = [ [[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.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d2e93f837d749c16d118e7ddf7a4dfd0ac8f452cf51e46e9348824e5ef6851" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek", "ed25519", - "rand 0.7.3", + "rand_core 0.6.4", "serde", - "sha2 0.9.9", + "sha2 0.10.6", + "subtle", "zeroize", ] @@ -580,30 +760,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4530da57967e140ee0b44e0143aa66b5cb42bd9c503dbe316a15d5b0be65713e" dependencies = [ "byteorder", - "ff_derive", "rand_core 0.5.1", ] [[package]] -name = "ff_derive" -version = "0.4.1" +name = "ff" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5796e7d62ca01a00ed3a649b0da1ffa1ac8f06bcad40339df09dbdd69a05ba9" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "num-bigint 0.2.6", - "num-integer", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", + "bitvec", + "rand_core 0.6.4", + "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "generic-array" version = "0.14.6" @@ -642,11 +830,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cbdfc48f95bef47e3daf3b9d552a1dde6311e3a5fefa43e16c59f651d56fe5b" dependencies = [ - "ff", + "ff 0.5.2", "rand 0.7.3", "rand_xorshift", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -668,7 +867,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", ] [[package]] @@ -818,10 +1017,9 @@ name = "keygen_bls" version = "2.0.0" dependencies = [ "concordium_base", - "ff", + "ff 0.5.2", "hex", "hkdf", - "pairing", "sha2 0.10.6", ] @@ -888,13 +1086,11 @@ dependencies = [ "ed25519-dalek", "ed25519_hd_key_derivation", "either", - "ff", "hex", "jni", "key_derivation", "libc", - "pairing", - "rand 0.7.3", + "rand 0.8.5", "serde", "serde_json", "sha2 0.10.6", @@ -917,7 +1113,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" dependencies = [ - "num-bigint 0.4.3", + "num-bigint", "num-complex", "num-integer", "num-iter", @@ -925,17 +1121,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -984,7 +1169,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint 0.4.3", + "num-bigint", "num-integer", "num-traits", ] @@ -1020,18 +1205,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "pairing" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94c40534479a28199cd5109da27fe2fc4a4728e4fc701d9e9c1bded78f3271e4" -dependencies = [ - "byteorder", - "ff", - "group", - "rand_core 0.5.1", -] - [[package]] name = "password-hash" version = "0.3.2" @@ -1043,6 +1216,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pbkdf2" version = "0.10.1" @@ -1055,6 +1234,22 @@ dependencies = [ "sha2 0.10.6", ] +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "platforms" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1072,9 +1267,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -1108,6 +1303,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.7.3" @@ -1422,9 +1623,12 @@ 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 = [ + "rand_core 0.6.4", +] [[package]] name = "simdutf8" @@ -1432,6 +1636,16 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.10.0" @@ -1467,16 +1681,10 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.12.6" +name = "tap" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "termcolor" @@ -1572,12 +1780,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "unreachable" version = "1.0.0" @@ -1713,23 +1915,51 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "zeroize" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.3.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", - "synstructure", + "syn 2.0.39", ] diff --git a/mobile_wallet/Cargo.toml b/mobile_wallet/Cargo.toml index 9f3a576ac..be96f642a 100644 --- a/mobile_wallet/Cargo.toml +++ b/mobile_wallet/Cargo.toml @@ -8,15 +8,13 @@ license-file = "../../LICENSE-APACHE" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -pairing = "0.15" -ff = "0.5" -rand = "=0.7" +rand = "=0.8" hex = "0.4" serde = "1.0" serde_json = "1.0" anyhow = "1.0" chrono = "0.4.24" # the patch version is necessary since chrono adds new functionality in patch versions -ed25519-dalek = "=1.0.0" +ed25519-dalek = "2.0" byteorder = "1.3" either = "1.6" sha2 = "0.10" diff --git a/mobile_wallet/src/lib.rs b/mobile_wallet/src/lib.rs index 753580a0a..8cb7be7bc 100644 --- a/mobile_wallet/src/lib.rs +++ b/mobile_wallet/src/lib.rs @@ -15,7 +15,7 @@ use concordium_base::{ hashes::{HashBytes, TransactionSignHash}, id::{ self, account_holder, - constants::{ArCurve, AttributeKind}, + constants::{ArCurve, AttributeKind, IpPairing}, id_proof_types::{ProofVersion, Statement, StatementWithContext}, pedersen_commitment::Value as PedersenValue, ps_sig, @@ -34,7 +34,6 @@ use concordium_base::{ use either::Either::{Left, Right}; use key_derivation::{ConcordiumHdWallet, CredentialContext, Net}; use libc::c_char; -use pairing::bls12_381::Bls12; use rand::thread_rng; use serde_json::{from_str, from_value, to_string, Value}; use sha2::{Digest, Sha256}; @@ -46,6 +45,8 @@ use std::{ str::FromStr, }; +type Bls12 = IpPairing; + /// Context for a transaction to send. #[derive(common::SerdeDeserialize)] #[serde(rename_all = "camelCase")] @@ -659,7 +660,7 @@ fn create_id_request_and_private_data_aux(input: &str) -> anyhow::Result let mut csprng = thread_rng(); keys.insert( KeyIndex(0), - concordium_base::common::types::KeyPair::from(ed25519_dalek::Keypair::generate( + concordium_base::common::types::KeyPair::from(ed25519_dalek::SigningKey::generate( &mut csprng, )), ); @@ -919,8 +920,8 @@ fn create_credential_v1_aux(input: &str) -> anyhow::Result { identity_index, u32::from(acc_num), )?; - let public = ed25519_dalek::PublicKey::from(&secret); - keys.insert(KeyIndex(0), KeyPair { secret, public }); + let signing_key = ed25519_dalek::SigningKey::from(&secret); + keys.insert(KeyIndex(0), signing_key.into()); CredentialData { keys, diff --git a/rust-bins/Cargo.lock b/rust-bins/Cargo.lock index 589968767..8e9da4913 100644 --- a/rust-bins/Cargo.lock +++ b/rust-bins/Cargo.lock @@ -89,6 +89,124 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -359,7 +477,7 @@ dependencies = [ "fnv", "hashbrown 0.11.2", "hex", - "num-bigint 0.4.4", + "num-bigint", "num-integer", "num-traits", "rust_decimal", @@ -383,6 +501,11 @@ version = "3.2.0" dependencies = [ "aes", "anyhow", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", "base64", "bs58", "byteorder", @@ -394,8 +517,8 @@ dependencies = [ "derive_more", "ed25519-dalek", "either", - "ff", - "group", + "ff 0.13.0", + "group 0.2.0", "hex", "hmac", "itertools", @@ -403,12 +526,10 @@ dependencies = [ "libc", "nom", "num", - "num-bigint 0.4.4", + "num-bigint", "num-traits", - "pairing", "pbkdf2 0.11.0", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", "rayon", "rust_decimal", "serde", @@ -443,6 +564,12 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "convert_case" version = "0.4.0" @@ -544,17 +671,34 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "group 0.13.0", + "platforms", + "rand_core 0.6.4", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "darling" version = "0.20.3" @@ -590,6 +734,16 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.8" @@ -599,6 +753,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -646,24 +811,25 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.3" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ + "pkcs8", "signature", ] [[package]] name = "ed25519-dalek" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ "curve25519-dalek", "ed25519", - "rand 0.7.3", + "rand_core 0.6.4", "serde", - "sha2 0.9.9", + "sha2 0.10.8", "zeroize", ] @@ -740,24 +906,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4530da57967e140ee0b44e0143aa66b5cb42bd9c503dbe316a15d5b0be65713e" dependencies = [ "byteorder", - "ff_derive", "rand_core 0.5.1", ] [[package]] -name = "ff_derive" -version = "0.4.1" +name = "ff" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5796e7d62ca01a00ed3a649b0da1ffa1ac8f06bcad40339df09dbdd69a05ba9" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "num-bigint 0.2.6", - "num-integer", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", + "bitvec", + "rand_core 0.6.4", + "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" + [[package]] name = "fnv" version = "1.0.7" @@ -886,11 +1054,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cbdfc48f95bef47e3daf3b9d552a1dde6311e3a5fefa43e16c59f651d56fe5b" dependencies = [ - "ff", + "ff 0.5.2", "rand 0.7.3", "rand_xorshift", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.3.21" @@ -1198,10 +1377,9 @@ name = "keygen_bls" version = "2.0.0" dependencies = [ "concordium_base", - "ff", + "ff 0.5.2", "hex", "hkdf", - "pairing", "sha2 0.10.8", ] @@ -1331,16 +1509,15 @@ dependencies = [ "ed25519-dalek", "ed25519_hd_key_derivation", "either", - "ff", + "ff 0.5.2", "hex", "hkdf", "hmac", "key_derivation", "keygen_bls", "openssl-sys", - "pairing", "pbkdf2 0.11.0", - "rand 0.7.3", + "rand 0.8.5", "reqwest", "rpassword", "serde", @@ -1393,7 +1570,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ - "num-bigint 0.4.4", + "num-bigint", "num-complex", "num-integer", "num-iter", @@ -1401,17 +1578,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.4" @@ -1460,7 +1626,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint 0.4.4", + "num-bigint", "num-integer", "num-traits", ] @@ -1559,18 +1725,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "pairing" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94c40534479a28199cd5109da27fe2fc4a4728e4fc701d9e9c1bded78f3271e4" -dependencies = [ - "byteorder", - "ff", - "group", - "rand_core 0.5.1", -] - [[package]] name = "parking_lot" version = "0.11.2" @@ -1618,6 +1772,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pbkdf2" version = "0.10.1" @@ -1660,12 +1820,28 @@ 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.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platforms" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2226,9 +2402,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" [[package]] name = "simdutf8" @@ -2271,6 +2447,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.8.0" @@ -2862,9 +3048,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.3.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] diff --git a/rust-bins/Cargo.toml b/rust-bins/Cargo.toml index 9f5dc9d53..bc3499cd5 100644 --- a/rust-bins/Cargo.toml +++ b/rust-bins/Cargo.toml @@ -13,12 +13,11 @@ vendored-ssl = ["openssl-sys/vendored"] [dependencies] clap = "2.33" dialoguer = "0.10" -pairing = "0.15" -rand = "=0.7" +rand = "=0.8" serde = "1.0" serde_json = "1.0" -ed25519-dalek = "=1.0" -curve25519-dalek = "3.0" +ed25519-dalek = "2.0" +curve25519-dalek = "4.0" structopt = "0.3" hex = "0.4" sha2 = "0.10" diff --git a/rust-bins/src/bin/client.rs b/rust-bins/src/bin/client.rs index 8df065e54..61afc4660 100644 --- a/rust-bins/src/bin/client.rs +++ b/rust-bins/src/bin/client.rs @@ -23,7 +23,6 @@ use dialoguer::{Input, MultiSelect, Select}; use ed25519_dalek as ed25519; use either::Either::{Left, Right}; use key_derivation::{ConcordiumHdWallet, CredentialContext, Net}; -use pairing::bls12_381::{Bls12, G1}; use rand::*; use serde_json::{json, to_value}; use std::{ @@ -36,6 +35,9 @@ use std::{ }; use structopt::StructOpt; +type Bls12 = IpPairing; +type G1 = ArCurve; + static IP_NAME_PREFIX: &str = "identity_provider-"; static AR_NAME_PREFIX: &str = "AR-"; @@ -1144,8 +1146,8 @@ fn handle_create_credential(cc: CreateCredential) { }; let cred_data = { let mut keys = std::collections::BTreeMap::new(); - let public = ed25519::PublicKey::from(&secret); - keys.insert(KeyIndex(0), KeyPair { secret, public }); + let signing_key = ed25519::SigningKey::from(&secret); + keys.insert(KeyIndex(0), signing_key.into()); CredentialData { keys, @@ -2221,9 +2223,10 @@ fn handle_generate_ips(gip: GenerateIps) { let id_secret_key = ps_sig::SecretKey::::generate(gip.key_capacity, &mut csprng); let id_public_key = ps_sig::PublicKey::from(&id_secret_key); - let keypair = ed25519::Keypair::generate(&mut csprng); - let ip_cdi_verify_key = keypair.public; - let ip_cdi_secret_key = keypair.secret; + let signing_key = ed25519::SigningKey::generate(&mut csprng); + let secret_key = signing_key.to_bytes(); + let ip_cdi_verify_key = signing_key.verifying_key(); + let ip_cdi_secret_key = secret_key; let ip_id = IpIdentity(id as u32); let ip_info = IpInfo { diff --git a/rust-bins/src/bin/generate_testdata.rs b/rust-bins/src/bin/generate_testdata.rs index d51653323..087451412 100644 --- a/rust-bins/src/bin/generate_testdata.rs +++ b/rust-bins/src/bin/generate_testdata.rs @@ -17,11 +17,13 @@ use concordium_base::{ ps_sig, }; use either::{Left, Right}; -use pairing::bls12_381::{Bls12, G1}; use rand::*; use std::{collections::btree_map::BTreeMap, fs::File, io::Write, path::PathBuf}; use structopt::StructOpt; +type Bls12 = IpPairing; +type G1 = ArCurve; + type ExampleAttribute = AttributeKind; type ExampleAttributeList = AttributeList<::ScalarField, ExampleAttribute>; @@ -478,6 +480,7 @@ fn main() { generate_initial(prf_key, 2, &ip_cdi_secret_key); generate_initial(prf_key_same, 3, &ip_cdi_secret_key); // Reuse of prf key let prf_key: prf::SecretKey = prf::SecretKey::generate(&mut csprng); - let wrong_keys = ed25519_dalek::Keypair::generate(&mut csprng); - generate_initial(prf_key, 4, &wrong_keys.secret); // Wrong secret key + let mut wrong_keys = ed25519_dalek::SecretKey::default(); + csprng.fill_bytes(&mut wrong_keys); + generate_initial(prf_key, 4, &wrong_keys); // Wrong secret key } diff --git a/rust-bins/src/bin/identity_provider_cli.rs b/rust-bins/src/bin/identity_provider_cli.rs index d270c6294..7e18175e7 100644 --- a/rust-bins/src/bin/identity_provider_cli.rs +++ b/rust-bins/src/bin/identity_provider_cli.rs @@ -11,10 +11,11 @@ use concordium_base::{ }, }; use dialoguer::Input; -use pairing::bls12_381::Bls12; use std::{collections::btree_map::BTreeMap, path::PathBuf}; use structopt::StructOpt; +type Bls12 = IpPairing; + #[derive(StructOpt)] #[structopt( about = "Command line client that supports issuing identities for enterprises.", diff --git a/rust-bins/src/bin/keygen-genesis.rs b/rust-bins/src/bin/keygen-genesis.rs index 994d4bd0b..927d1a950 100644 --- a/rust-bins/src/bin/keygen-genesis.rs +++ b/rust-bins/src/bin/keygen-genesis.rs @@ -1,14 +1,24 @@ use clap::AppSettings; use client_server_helpers::*; use concordium_base::{ - common::*, curve_arithmetic::Curve, elgamal::PublicKey, id::types::*, ps_sig, + common::*, + curve_arithmetic::Curve, + elgamal::PublicKey, + id::{ + constants::{ArCurve, BlsG2, IpPairing}, + types::*, + }, + ps_sig, }; use curve25519_dalek::edwards::CompressedEdwardsY; -use pairing::bls12_381::{Bls12, G1, G2}; use sha2::{Digest, Sha512}; use std::{fs, path::PathBuf}; use structopt::StructOpt; +type Bls12 = IpPairing; +type G1 = ArCurve; +type G2 = BlsG2; + #[derive(StructOpt)] struct KeygenIp { #[structopt(long = "seed", help = "File with seed.")] @@ -104,8 +114,10 @@ macro_rules! succeed_or_die { fn handle_generate_ar_keys(kgar: KeygenAr) -> Result<(), String> { let bytes_from_file = succeed_or_die!(fs::read(kgar.seed), e => "Could not read random input from provided file because {}"); - let generator = G1::hash_to_group(&bytes_from_file); - let key = G1::hash_to_group(&to_bytes(&generator)); + let generator = + G1::hash_to_group(&bytes_from_file).expect("Hashing to curve expected to succeed"); + let key = + G1::hash_to_group(&to_bytes(&generator)).expect("Hashing to curve expected to succeed"); let ar_public_key = PublicKey { generator, key }; let ar_identity = kgar.ar_identity; let name = kgar.name; @@ -174,15 +186,19 @@ fn handle_generate_ip_keys(kgip: KeygenIp) -> Result<(), String> { pub fn generate_ps_pk(n: u32, bytes: &[u8]) -> ps_sig::PublicKey { let mut ys: Vec = Vec::with_capacity(n as usize); let mut y_tildas: Vec = Vec::with_capacity(n as usize); - let mut g1_element = G1::hash_to_group(bytes); - let mut g2_element = G2::hash_to_group(&to_bytes(&g1_element)); + let mut g1_element = G1::hash_to_group(bytes).expect("Hashing to curve expected to succeed"); + let mut g2_element = + G2::hash_to_group(&to_bytes(&g1_element)).expect("Hashing to curve expected to succeed"); for _ in 0..n { ys.push(g1_element); y_tildas.push(g2_element); - g1_element = G1::hash_to_group(&to_bytes(&g2_element)); - g2_element = G2::hash_to_group(&to_bytes(&g1_element)); + g1_element = G1::hash_to_group(&to_bytes(&g2_element)) + .expect("Hashing to curve expected to succeed"); + g2_element = G2::hash_to_group(&to_bytes(&g1_element)) + .expect("Hashing to curve expected to succeed"); } - let x_tilda = G2::hash_to_group(&to_bytes(&g2_element)); + let x_tilda = + G2::hash_to_group(&to_bytes(&g2_element)).expect("Hashing to curve expected to succeed"); ps_sig::PublicKey { g: G1::one_point(), g_tilda: G2::one_point(), @@ -196,7 +212,7 @@ pub fn generate_ps_pk(n: u32, bytes: &[u8]) -> ps_sig::PublicKey { /// The difference is that this one does not concatenate the input /// to Sha512 with the single octet values 0 and 1, and neither does it /// concatenate with a public key. -pub fn hash_to_ed25519(msg: &[u8]) -> Option { +pub fn hash_to_ed25519(msg: &[u8]) -> Option { let mut p_candidate_bytes = [0u8; 32]; let mut h: Sha512 = Sha512::new(); h.update(b"concordium_genesis_ed25519"); @@ -212,7 +228,7 @@ pub fn hash_to_ed25519(msg: &[u8]) -> Option { // not be 0 after multiplying by cofactor. if !ed_point.is_small_order() { return Some( - ed25519_dalek::PublicKey::from_bytes( + ed25519_dalek::VerifyingKey::from_bytes( &ed_point.mul_by_cofactor().compress().to_bytes(), ) .unwrap(), diff --git a/rust-bins/src/bin/keygen.rs b/rust-bins/src/bin/keygen.rs index 617bd0cf0..8bb2e0280 100644 --- a/rust-bins/src/bin/keygen.rs +++ b/rust-bins/src/bin/keygen.rs @@ -4,7 +4,10 @@ use concordium_base::{ common::*, curve_arithmetic::Curve, elgamal::{PublicKey, SecretKey}, - id::types::*, + id::{ + constants::{ArCurve, BaseField, BlsG2, IpPairing}, + types::*, + }, ps_sig, }; use crossterm::{ @@ -12,9 +15,9 @@ use crossterm::{ terminal::{Clear, ClearType}, }; use dialoguer::{Confirm, Input}; +use ed25519_dalek::SigningKey; use hmac::{Hmac, Mac}; use keygen_bls::{keygen_bls, keygen_bls_deprecated}; -use pairing::bls12_381::{Bls12, Fr, G1, G2}; use sha2::Sha512; use std::{ collections::HashMap, @@ -25,6 +28,11 @@ use std::{ }; use structopt::StructOpt; +type Bls12 = IpPairing; +type G1 = ArCurve; +type G2 = BlsG2; +type Fr = BaseField; + const BIP39_ENGLISH: &str = include_str!("data/BIP39English.txt"); /// List of BIP39 words. There is a test that checks that this list has correct @@ -289,7 +297,8 @@ pub fn read_words_from_file( fn handle_generate_update_keys(kgup: KeygenGovernance) -> Result<(), String> { let mut csprng = rand::thread_rng(); let keypair = concordium_base::common::types::KeyPair::generate(&mut csprng); - let public_bytes = keypair.public.to_bytes(); + let signing_key: &SigningKey = keypair.as_ref(); + let public_bytes = signing_key.verifying_key().to_bytes(); let sig = keypair.sign(&public_bytes); let level_str = match kgup.level { Level::Root => "root", @@ -298,10 +307,10 @@ fn handle_generate_update_keys(kgup: KeygenGovernance) -> Result<(), String> { }; let public_data = serde_json::json!({ "key": { - "verifyKey": base16_encode_string(&keypair.public), + "verifyKey": base16_encode_string(&signing_key.verifying_key()), "scheme": "Ed25519", }, - "signature": sig, + "signature": base16_encode_string(&sig), "type": level_str, }); let secret_data = serde_json::json!({ @@ -529,8 +538,9 @@ fn handle_generate_ip_keys(kgip: KeygenIp) -> Result<(), String> { println!("Using deprecated BLS keygen."); } let ip_public_key = ps_sig::PublicKey::from(&ip_secret_key); - let ed_sk = succeed_or_die!(generate_ed_sk(&bytes_from_file), e => "Could not generate signature key for EdDSA because {}"); - let ed_pk = ed25519_dalek::PublicKey::from(&ed_sk); + let ed_sk = generate_ed_sk(&bytes_from_file); + let signing_key = ed25519_dalek::SigningKey::from_bytes(&ed_sk); + let ed_pk = signing_key.verifying_key(); let ip_cdi_verify_key = ed_pk; let ip_cdi_secret_key = ed_sk; let id = kgip.ip_identity; @@ -665,12 +675,7 @@ pub fn keygen_ed(seed: &[u8]) -> [u8; 32] { /// It generates a ed25519_dalek secret key given a seed, using the `keygen_ed` /// above. -pub fn generate_ed_sk( - seed: &[u8], -) -> Result { - let sk = ed25519_dalek::SecretKey::from_bytes(&keygen_ed(seed))?; - Ok(sk) -} +pub fn generate_ed_sk(seed: &[u8]) -> ed25519_dalek::SecretKey { keygen_ed(seed) } #[cfg(test)] mod tests { diff --git a/rust-bins/src/bin/user_cli.rs b/rust-bins/src/bin/user_cli.rs index 21c1ec78a..8aae939f9 100644 --- a/rust-bins/src/bin/user_cli.rs +++ b/rust-bins/src/bin/user_cli.rs @@ -788,8 +788,8 @@ fn handle_create_credential_v1(cc: CreateCredentialV1) -> anyhow::Result<()> { }; let acc_data = { let mut keys = std::collections::BTreeMap::new(); - let public = ed25519::PublicKey::from(&secret); - keys.insert(KeyIndex(0), KeyPair { secret, public }); + let signing_key = ed25519::SigningKey::from_bytes(&secret); + keys.insert(KeyIndex(0), signing_key.into()); CredentialData { keys, diff --git a/rust-bins/src/lib.rs b/rust-bins/src/lib.rs index bb98a8039..4b7de1a82 100644 --- a/rust-bins/src/lib.rs +++ b/rust-bins/src/lib.rs @@ -7,7 +7,6 @@ use concordium_base::{ }; use dialoguer::Input; use hkdf::HkdfExtract; -use pairing::bls12_381::Bls12; use rand::Rng; use serde::{de::DeserializeOwned, Serialize as SerdeSerialize}; use serde_json::{to_string_pretty, to_writer_pretty}; @@ -21,6 +20,8 @@ use std::{ str::FromStr, }; +type Bls12 = IpPairing; + pub type ExampleAttribute = AttributeKind; pub type ExampleAttributeList = AttributeList<::ScalarField, ExampleAttribute>; diff --git a/rust-src/Cargo.lock b/rust-src/Cargo.lock index f2e10f6e9..c6291c532 100644 --- a/rust-src/Cargo.lock +++ b/rust-src/Cargo.lock @@ -71,6 +71,124 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -359,7 +477,7 @@ dependencies = [ "fnv", "hashbrown 0.11.2", "hex", - "num-bigint 0.4.4", + "num-bigint", "num-integer", "num-traits", "rust_decimal", @@ -383,6 +501,11 @@ version = "3.2.0" dependencies = [ "aes", "anyhow", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", "base64", "bs58", "byteorder", @@ -395,8 +518,8 @@ dependencies = [ "derive_more", "ed25519-dalek", "either", - "ff", - "group", + "ff 0.13.0", + "group 0.2.0", "hex", "hmac", "itertools", @@ -404,12 +527,10 @@ dependencies = [ "libc", "nom", "num", - "num-bigint 0.4.4", + "num-bigint", "num-traits", - "pairing", "pbkdf2 0.11.0", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", "rayon", "rust_decimal", "serde", @@ -431,6 +552,12 @@ dependencies = [ "syn 2.0.32", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "convert_case" version = "0.4.0" @@ -543,17 +670,34 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "group 0.13.0", + "platforms", + "rand_core 0.6.4", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + [[package]] name = "darling" version = "0.20.3" @@ -589,6 +733,16 @@ dependencies = [ "syn 2.0.32", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.8" @@ -598,6 +752,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -633,24 +798,25 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.3" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ + "pkcs8", "signature", ] [[package]] name = "ed25519-dalek" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ "curve25519-dalek", "ed25519", - "rand 0.7.3", + "rand_core 0.6.4", "serde", - "sha2 0.9.9", + "sha2 0.10.7", "zeroize", ] @@ -685,24 +851,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4530da57967e140ee0b44e0143aa66b5cb42bd9c503dbe316a15d5b0be65713e" dependencies = [ "byteorder", - "ff_derive", "rand_core 0.5.1", ] [[package]] -name = "ff_derive" -version = "0.4.1" +name = "ff" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5796e7d62ca01a00ed3a649b0da1ffa1ac8f06bcad40339df09dbdd69a05ba9" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "num-bigint 0.2.6", - "num-integer", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", + "bitvec", + "rand_core 0.6.4", + "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" + [[package]] name = "fnv" version = "1.0.7" @@ -753,11 +921,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cbdfc48f95bef47e3daf3b9d552a1dde6311e3a5fefa43e16c59f651d56fe5b" dependencies = [ - "ff", + "ff 0.5.2", "rand 0.7.3", "rand_xorshift", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "half" version = "1.8.2" @@ -948,10 +1127,9 @@ name = "keygen_bls" version = "2.0.0" dependencies = [ "concordium_base", - "ff", + "ff 0.5.2", "hex", "hkdf", - "pairing", "sha2 0.10.7", ] @@ -969,9 +1147,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "log" @@ -1016,7 +1194,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ - "num-bigint 0.4.4", + "num-bigint", "num-complex", "num-integer", "num-iter", @@ -1024,17 +1202,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.4" @@ -1083,7 +1250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint 0.4.4", + "num-bigint", "num-integer", "num-traits", ] @@ -1131,18 +1298,6 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" -[[package]] -name = "pairing" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94c40534479a28199cd5109da27fe2fc4a4728e4fc701d9e9c1bded78f3271e4" -dependencies = [ - "byteorder", - "ff", - "group", - "rand_core 0.5.1", -] - [[package]] name = "password-hash" version = "0.3.2" @@ -1165,6 +1320,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pbkdf2" version = "0.10.1" @@ -1189,6 +1350,22 @@ dependencies = [ "sha2 0.10.7", ] +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "platforms" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" + [[package]] name = "plotters" version = "0.3.5" @@ -1287,7 +1464,6 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg", ] [[package]] @@ -1348,15 +1524,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "rand_xorshift" version = "0.2.0" @@ -1615,9 +1782,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" [[package]] name = "simdutf8" @@ -1625,6 +1792,16 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.10.0" @@ -1985,9 +2162,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.3.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] diff --git a/rust-src/concordium_base/CHANGELOG.md b/rust-src/concordium_base/CHANGELOG.md index 126ed4283..98d525185 100644 --- a/rust-src/concordium_base/CHANGELOG.md +++ b/rust-src/concordium_base/CHANGELOG.md @@ -1,9 +1,18 @@ ## Unreleased changes -- Improve performance of `multiexp*` family of functions. -- Add traits `Field` and `PrimeField` with implementations for the underlying field of the `BLS12-381` curve. - Add `MultiExp` trait that allows to have different `multiexp` algorithm implementations for different curves. +- Improve performance of the generic `multiexp` algorithm. +- Add an instance of `MultiExp` that is specific to `curve25519`. +- Add traits `Field` and `PrimeField` with implementations for the underlying field of the `BLS12-381` curve. +- Add integration with the `arkworks` library interfaces for fields and elliptic curves (wrapper types and blanket trait implementations). +- Add the `BLS12-381`implementation from the `arkworks` ecosystem. +- The public types `id::constants::ArCurve`, `id::constants::IpPairing` are defined in terms of the `arkworks` BLS12-381 implementation. +- Add a type alias `id::constants::BlsG2` for the `G2` group of `arkworks` BLS12-381. +- Upgrade `ed25519-dalek` to `v2.0`. +- Bump the `rand` version to `v0.8` - Add implementations of `Field`, `PrimeField` and `Curve` for the Ristretto representation of `curve25519`. +- Remove `Curve::bytes_to_curve_unchecked()`. +- Rename `Cipher::from_bytes_unchecked()` to `Cipher::from_bytes()`; the method uses `deserial()` instead of `Curve::bytes_to_curve_unchecked()`. - Support `P7` protocol version. - The `Debug` implementation for `ContractEvent` displays the value in `hex`. The alternate formatter (using `#`) displays it as a list of bytes. diff --git a/rust-src/concordium_base/Cargo.toml b/rust-src/concordium_base/Cargo.toml index 56b02c281..fea6662ef 100644 --- a/rust-src/concordium_base/Cargo.toml +++ b/rust-src/concordium_base/Cargo.toml @@ -12,28 +12,31 @@ repository = "https://github.com/Concordium/concordium-base" homepage = "https://github.com/Concordium/concordium-base" [dependencies] -ff = "0.5" +ff = "0.13" +ark-ff = { version = "0.4"} +ark-ec = { version = "0.4"} +ark-serialize = { version = "0.4"} +ark-std = { version = "0.4"} +ark-bls12-381 = { version = "0.4"} sha2 = "0.10" sha3 = "0.10" anyhow = "1.0" -rand_core = "=0.5" serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" libc = "0.2" chrono = {version = "0.4.24", features = ["serde"]} # the patch version is necessary since chrono adds new functionality in patch versions serde_with = "3" -ed25519-dalek = "=1.0" +ed25519-dalek = {version = "2.0", features = ["rand_core"]} byteorder = "1.3" hex = "0.4" itertools = "0.10" either = "1.6" -pairing = "0.15" derive_more = "0.99" thiserror = "1.0" -rand = "0.7" +rand = "0.8" num = "0.4" group = "0.2" -curve25519-dalek = "3" +curve25519-dalek = { version = "4.1", features = ["rand_core", "group"]} zeroize = "1.1" # See https://github.com/serde-rs/json/issues/505 for the need to be careful. rust_decimal = { version = "1.25", features = ["serde-float", "serde-arbitrary-precision"]} @@ -74,7 +77,7 @@ encryption = ["cbc", "aes", "base64", "pbkdf2", "hmac"] [dev-dependencies] criterion = "0.4" -rand = {version = "0.7", features = ["small_rng"]} +rand = {version = "0.8", features = ["small_rng"]} [[bench]] name = "hash_bench" diff --git a/rust-src/concordium_base/benches/aggr_dlog_commit_message.rs b/rust-src/concordium_base/benches/aggr_dlog_commit_message.rs index 84e14fa66..48a5066fc 100644 --- a/rust-src/concordium_base/benches/aggr_dlog_commit_message.rs +++ b/rust-src/concordium_base/benches/aggr_dlog_commit_message.rs @@ -1,11 +1,13 @@ +use ark_bls12_381::G1Projective; use concordium_base::{ - curve_arithmetic::*, + curve_arithmetic::{arkworks_instances::ArkGroup, *}, sigma_protocols::{aggregate_dlog::*, common::*}, }; use criterion::*; -use pairing::bls12_381::G1; use rand::*; +type G1 = ArkGroup; + /// Benchmark the aggregate dlog sigma protocol fn bench_aggr_dlog_commit_message(c: &mut Criterion) { let mut csprng = thread_rng(); diff --git a/rust-src/concordium_base/benches/aggregate_signatures.rs b/rust-src/concordium_base/benches/aggregate_signatures.rs index 366a23143..fa0b4c8a5 100644 --- a/rust-src/concordium_base/benches/aggregate_signatures.rs +++ b/rust-src/concordium_base/benches/aggregate_signatures.rs @@ -1,8 +1,9 @@ use concordium_base::aggregate_sig::*; use criterion::*; -use pairing::bls12_381::Bls12; use rand::{thread_rng, Rng}; +type Bls12 = ark_ec::bls12::Bls12; + macro_rules! rand_m_of_length { ($length:expr, $rng:expr) => {{ let mut m: Vec = Vec::with_capacity($length); diff --git a/rust-src/concordium_base/benches/bulletproofs.rs b/rust-src/concordium_base/benches/bulletproofs.rs index 4c6b77839..e9249bd3b 100644 --- a/rust-src/concordium_base/benches/bulletproofs.rs +++ b/rust-src/concordium_base/benches/bulletproofs.rs @@ -3,19 +3,21 @@ #[macro_use] extern crate criterion; +use ark_bls12_381::{Fr, G1Projective}; use concordium_base::{ bulletproofs::{inner_product_proof::*, range_proof::*, utils::Generators}, - curve_arithmetic::*, + curve_arithmetic::{arkworks_instances::ArkGroup, *}, id::id_proof_types::ProofVersion, pedersen_commitment::*, random_oracle::RandomOracle, }; use criterion::Criterion; use curve25519_dalek::ristretto::RistrettoPoint; -use pairing::bls12_381::G1; use rand::*; use std::time::Duration; +type G1 = ArkGroup; + pub fn prove_verify_benchmarks(c: &mut Criterion) { let bench_group_name = "Range Proof for ".to_owned() + std::any::type_name::(); let mut group = c.benchmark_group(bench_group_name); diff --git a/rust-src/concordium_base/benches/commitment_to_share.rs b/rust-src/concordium_base/benches/commitment_to_share.rs index dba0f21d8..e6e5f645f 100644 --- a/rust-src/concordium_base/benches/commitment_to_share.rs +++ b/rust-src/concordium_base/benches/commitment_to_share.rs @@ -1,10 +1,14 @@ +use ark_bls12_381::G1Projective; use concordium_base::{ - curve_arithmetic::*, id::utils::commitment_to_share, pedersen_commitment::Commitment, + curve_arithmetic::{arkworks_instances::ArkGroup, *}, + id::utils::commitment_to_share, + pedersen_commitment::Commitment, }; use criterion::*; -use pairing::bls12_381::G1; use rand::*; +type G1 = ArkGroup; + fn bench_commitment_to_share(c: &mut Criterion) { let mut csprng = thread_rng(); diff --git a/rust-src/concordium_base/benches/compute_message.rs b/rust-src/concordium_base/benches/compute_message.rs index 3c8655228..012faede9 100644 --- a/rust-src/concordium_base/benches/compute_message.rs +++ b/rust-src/concordium_base/benches/compute_message.rs @@ -1,6 +1,7 @@ +use ark_bls12_381::G1Projective; use concordium_base::{ common::types::*, - curve_arithmetic::*, + curve_arithmetic::{arkworks_instances::ArkGroup, *}, id, id::{ constants::*, @@ -13,7 +14,6 @@ use concordium_base::{ ps_sig, }; use criterion::*; -use pairing::bls12_381::{G1, *}; use rand::*; use serde_json::from_str; use std::{ @@ -21,6 +21,9 @@ use std::{ convert::TryFrom, }; +type G1 = ArkGroup; +type Bls12 = ark_ec::bls12::Bls12; + fn bench_compute_message(c: &mut Criterion) { let mut csprng = thread_rng(); diff --git a/rust-src/concordium_base/benches/eddsa_benchmarks.rs b/rust-src/concordium_base/benches/eddsa_benchmarks.rs index 560b9976d..8fb3240c2 100644 --- a/rust-src/concordium_base/benches/eddsa_benchmarks.rs +++ b/rust-src/concordium_base/benches/eddsa_benchmarks.rs @@ -9,17 +9,13 @@ use rand::*; pub fn bench_from_bytes(c: &mut Criterion) { let mut csprng = thread_rng(); - let n = 32; - let mut a: Vec = Vec::with_capacity(n); - for _ in 0..n { - a.push(csprng.gen::()); - } - let ca = a.clone(); - c.bench_function("PublicKey::from_bytes {}", move |b| { - b.iter(|| PublicKey::from_bytes(&a).is_ok()) + let mut a = [0u8; 32]; + csprng.fill_bytes(&mut a); + c.bench_function("VerifyingKey::from_bytes {}", move |b| { + b.iter(|| VerifyingKey::from_bytes(&a).is_ok()) }); - c.bench_function("SecretKey::from_bytes {}", move |b| { - b.iter(|| SecretKey::from_bytes(&ca).is_ok()) + c.bench_function("SigningKey::from_bytes {}", move |b| { + b.iter(|| SigningKey::from_bytes(&a)) }); } @@ -32,12 +28,11 @@ pub fn bench_sign(c: &mut Criterion) { } let d = a.clone(); - let sk = SecretKey::generate(&mut csprng); - let pk = PublicKey::from(&sk); - let expanded_sk = ExpandedSecretKey::from(&sk); - let sig = expanded_sk.sign(a.as_slice(), &pk); + let signing_key = SigningKey::generate(&mut csprng); + let pk = signing_key.verifying_key(); + let sig = signing_key.sign(a.as_slice()); c.bench_function("sign {}", move |b| { - b.iter(|| expanded_sk.sign(a.as_slice(), &pk)) + b.iter(|| signing_key.sign(a.as_slice())) }); c.bench_function("verify{}", move |b| { b.iter(|| pk.verify(d.as_slice(), &sig)) diff --git a/rust-src/concordium_base/benches/elgamal_benchmarks.rs b/rust-src/concordium_base/benches/elgamal_benchmarks.rs index 1e8a0fd28..0bb433ab6 100644 --- a/rust-src/concordium_base/benches/elgamal_benchmarks.rs +++ b/rust-src/concordium_base/benches/elgamal_benchmarks.rs @@ -1,3 +1,4 @@ +use ark_bls12_381::G1Projective; use rand::*; #[macro_use] @@ -5,12 +6,18 @@ extern crate criterion; use criterion::Criterion; -use concordium_base::elgamal::*; - -use concordium_base::curve_arithmetic::Curve; -use ff::PrimeField; -use pairing::bls12_381::{Fr, G1}; -use std::time::Duration; +use concordium_base::{ + curve_arithmetic::{ + arkworks_instances::{ArkField, ArkGroup}, + Curve, + }, + elgamal::*, + id::constants::{ArCurve, BaseField}, +}; +use std::{str::FromStr, time::Duration}; + +type G1 = ArCurve; +type Fr = BaseField; pub fn baby_step_giant_step_table_bench(c: &mut Criterion) { let mut csprng = thread_rng(); diff --git a/rust-src/concordium_base/benches/encrypted_transfers_benchmarks.rs b/rust-src/concordium_base/benches/encrypted_transfers_benchmarks.rs index f41d00197..3702f5686 100644 --- a/rust-src/concordium_base/benches/encrypted_transfers_benchmarks.rs +++ b/rust-src/concordium_base/benches/encrypted_transfers_benchmarks.rs @@ -1,3 +1,4 @@ +use ark_bls12_381::G1Projective; use rand::*; #[macro_use] @@ -5,19 +6,20 @@ extern crate criterion; use concordium_base::{ common::types::Amount, - curve_arithmetic::Value, + curve_arithmetic::{arkworks_instances::ArkGroup, Value}, elgamal::{PublicKey, SecretKey}, encrypted_transfers::proofs::*, id::types::GlobalContext, random_oracle::*, }; use criterion::Criterion; -use pairing::bls12_381::G1; use std::time::Duration; +type G1 = ArkGroup; + pub fn generate_challenge_prefix(csprng: &mut R) -> Vec { // length of the challenge - let l = csprng.gen_range(0, 1000); + let l = csprng.gen_range(0..1000); let mut challenge_prefix = vec![0; l]; for v in challenge_prefix.iter_mut() { *v = csprng.gen(); @@ -35,7 +37,7 @@ pub fn enc_trans_bench(c: &mut Criterion) { let pk_receiver = PublicKey::from(&sk_receiver); let s = csprng.gen::(); // amount on account. - let a = csprng.gen_range(0, s); // amount to send + let a = csprng.gen_range(0..s); // amount to send let m = 2; // 2 chunks let n = 32; @@ -53,6 +55,7 @@ pub fn enc_trans_bench(c: &mut Criterion) { let context_clone = context.clone(); let sk_clone = sk_sender.clone(); + let mut csprng_clone = csprng.clone(); c.bench_function( &format!("{}: Create transaction with proofs", module_path!()), move |b| { @@ -67,7 +70,7 @@ pub fn enc_trans_bench(c: &mut Criterion) { &S, Amount::from_micro_ccd(s), Amount::from_micro_ccd(a), - &mut csprng, + &mut csprng_clone, ) .expect("Could not produce proof."); }) @@ -121,7 +124,7 @@ pub fn sec_to_pub_bench(c: &mut Criterion) { let pk = PublicKey::from(&sk); let s = csprng.gen::(); // amount on account. - let a = csprng.gen_range(0, s); // amount to send + let a = csprng.gen_range(0..s); // amount to send let m = 2; // 2 chunks let n = 32; @@ -139,6 +142,7 @@ pub fn sec_to_pub_bench(c: &mut Criterion) { let context_clone = context.clone(); let sk_clone = sk.clone(); + let mut csprng_clone = csprng.clone(); c.bench_function( &format!( "{}: Create sec to pub transaction with proofs", @@ -155,7 +159,7 @@ pub fn sec_to_pub_bench(c: &mut Criterion) { &S, Amount::from_micro_ccd(s), Amount::from_micro_ccd(a), - &mut csprng, + &mut csprng_clone, ) .expect("Could not produce proof."); }) diff --git a/rust-src/concordium_base/benches/hash_bench.rs b/rust-src/concordium_base/benches/hash_bench.rs index c072af72c..e60a9fc69 100644 --- a/rust-src/concordium_base/benches/hash_bench.rs +++ b/rust-src/concordium_base/benches/hash_bench.rs @@ -1,11 +1,13 @@ #[macro_use] extern crate criterion; -use concordium_base::curve_arithmetic::*; +use ark_bls12_381::G1Projective; +use concordium_base::curve_arithmetic::{arkworks_instances::ArkGroup, Curve}; use criterion::Criterion; -use pairing::bls12_381::G1; use rand::*; +type G1 = ArkGroup; + macro_rules! rand_m_of_length { ($length:expr, $rng:expr) => {{ let mut m: Vec = Vec::with_capacity($length); diff --git a/rust-src/concordium_base/benches/multiexp_bench.rs b/rust-src/concordium_base/benches/multiexp_bench.rs index 018c4e1dc..b4b733417 100644 --- a/rust-src/concordium_base/benches/multiexp_bench.rs +++ b/rust-src/concordium_base/benches/multiexp_bench.rs @@ -1,13 +1,15 @@ #[macro_use] extern crate criterion; -use concordium_base::curve_arithmetic::*; +use ark_bls12_381::G1Projective; +use concordium_base::curve_arithmetic::{arkworks_instances::ArkGroup, *}; use criterion::Criterion; use curve25519_dalek::ristretto::RistrettoPoint; -use pairing::bls12_381::G1; use rand::*; use std::time::Duration; +type G1 = ArkGroup; + pub fn bench_multiexp_bls(c: &mut Criterion) { let mut csprng = thread_rng(); let m = 3; diff --git a/rust-src/concordium_base/benches/serialization_benches.rs b/rust-src/concordium_base/benches/serialization_benches.rs index 3449e5c5d..2add0b8a9 100644 --- a/rust-src/concordium_base/benches/serialization_benches.rs +++ b/rust-src/concordium_base/benches/serialization_benches.rs @@ -3,14 +3,17 @@ #[macro_use] extern crate criterion; +use ark_bls12_381::{G1Projective, G2Projective}; use concordium_base::{ common::{Deserial, Serial}, - curve_arithmetic::*, + curve_arithmetic::{arkworks_instances::ArkGroup, *}, }; use criterion::Criterion; -use pairing::bls12_381::{G1, G2}; use rand::*; +type G1 = ArkGroup; +type G2 = ArkGroup; + pub fn bench_serialize_g1(c: &mut Criterion) { let mut csprng = thread_rng(); let elem = G1::generate(&mut csprng); diff --git a/rust-src/concordium_base/benches/set_proof_bench.rs b/rust-src/concordium_base/benches/set_proof_bench.rs index cd2b1287e..3dd9e5d3f 100644 --- a/rust-src/concordium_base/benches/set_proof_bench.rs +++ b/rust-src/concordium_base/benches/set_proof_bench.rs @@ -2,18 +2,20 @@ #[macro_use] extern crate criterion; +use ark_bls12_381::G1Projective; use concordium_base::{ bulletproofs::{set_membership_proof, set_non_membership_proof, utils::Generators}, - curve_arithmetic::*, + curve_arithmetic::{arkworks_instances::ArkGroup, *}, id::id_proof_types::ProofVersion, pedersen_commitment::{CommitmentKey, Randomness}, random_oracle::RandomOracle, }; use criterion::{BenchmarkId, Criterion}; -use pairing::bls12_381::G1; use rand::*; use std::time::Duration; +type G1 = ArkGroup; + #[allow(non_snake_case)] pub fn bench_set_proofs(c: &mut Criterion) { let mut group = c.benchmark_group("Set Proofs"); @@ -34,7 +36,7 @@ pub fn bench_set_proofs(c: &mut Criterion) { } // Let w be an element in the set - let w_index = rng.gen_range(0, n); + let w_index = rng.gen_range(0..n); let w = the_set[w_index]; // Commit to v diff --git a/rust-src/concordium_base/benches/verify_cdi.rs b/rust-src/concordium_base/benches/verify_cdi.rs index 260c687ac..dd4874335 100644 --- a/rust-src/concordium_base/benches/verify_cdi.rs +++ b/rust-src/concordium_base/benches/verify_cdi.rs @@ -1,8 +1,10 @@ +use ark_bls12_381::G1Projective; use concordium_base::{ common::{ types::{KeyIndex, KeyPair, TransactionTime}, *, }, + curve_arithmetic::arkworks_instances::ArkGroup, dodis_yampolskiy_prf as prf, elgamal::{PublicKey, SecretKey}, id::{ @@ -18,10 +20,12 @@ use concordium_base::{ use criterion::*; use ed25519_dalek as ed25519; use either::Either::Left; -use pairing::bls12_381::{Bls12, G1}; use rand::*; use std::{collections::BTreeMap, convert::TryFrom, io::Cursor}; +type G1 = ArkGroup; +type Bls12 = ark_ec::bls12::Bls12; + type ExampleAttribute = AttributeKind; type ExampleAttributeList = AttributeList; @@ -35,7 +39,7 @@ fn bench_parts(c: &mut Criterion) { let ip_secret_key = concordium_base::ps_sig::SecretKey::::generate(20, &mut csprng); let ip_public_key = concordium_base::ps_sig::PublicKey::from(&ip_secret_key); - let keypair = ed25519::Keypair::generate(&mut csprng); + let keypair = ed25519::SigningKey::generate(&mut csprng); let ah_info = CredentialHolderInfo:: { id_cred: IdCredentials::generate(&mut csprng), @@ -83,7 +87,7 @@ fn bench_parts(c: &mut Criterion) { ip_identity: IpIdentity(88), ip_description: mk_dummy_description("IP88".to_string()), ip_verify_key: ip_public_key, - ip_cdi_verify_key: keypair.public, + ip_cdi_verify_key: keypair.verifying_key(), }; let prf_key = prf::SecretKey::generate(&mut csprng); @@ -148,7 +152,7 @@ fn bench_parts(c: &mut Criterion) { &alist, EXPIRY, &ip_secret_key, - &keypair.secret, + &keypair.to_bytes(), ); let (ip_sig, initial_cdi) = ver_ok.unwrap(); @@ -263,7 +267,7 @@ fn bench_parts(c: &mut Criterion) { &id_object.alist, EXPIRY, &ip_secret_key, - &keypair.secret, + &keypair.to_bytes(), ) .unwrap() }) diff --git a/rust-src/concordium_base/src/aggregate_sig/ffi.rs b/rust-src/concordium_base/src/aggregate_sig/ffi.rs index 27a0d2042..8ec079000 100644 --- a/rust-src/concordium_base/src/aggregate_sig/ffi.rs +++ b/rust-src/concordium_base/src/aggregate_sig/ffi.rs @@ -2,10 +2,11 @@ use super::*; use crate::{common::*, ffi_helpers::*, random_oracle::RandomOracle, sigma_protocols::dlog}; -use pairing::bls12_381::Bls12; use rand::{rngs::StdRng, thread_rng, SeedableRng}; use std::{cmp::Ordering, slice}; +type Bls12 = ark_ec::bls12::Bls12; + #[no_mangle] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub extern "C" fn bls_generate_secretkey() -> *mut SecretKey { diff --git a/rust-src/concordium_base/src/aggregate_sig/mod.rs b/rust-src/concordium_base/src/aggregate_sig/mod.rs index 0b1566f32..039392763 100644 --- a/rust-src/concordium_base/src/aggregate_sig/mod.rs +++ b/rust-src/concordium_base/src/aggregate_sig/mod.rs @@ -31,7 +31,7 @@ impl SecretKey

{ /// Sign a message using the SecretKey pub fn sign(&self, m: &[u8]) -> Signature

{ - let g1_hash = P::G1::hash_to_group(m); + let g1_hash = P::G1::hash_to_group(m).expect("Hashing to curve expected to succeed"); let signature = g1_hash.mul_by_scalar(&self.0); Signature(signature) } @@ -84,7 +84,7 @@ impl PublicKey

{ /// For now, the generator used is the default generator of the underlying /// library however, this should be parametrized in the future pub fn verify(&self, m: &[u8], signature: Signature

) -> bool { - let g1_hash = P::G1::hash_to_group(m); + let g1_hash = P::G1::hash_to_group(m).expect("Hashing to curve expected to succeed"); // compute pairings in parallel P::check_pairing_eq(&signature.0, &P::G2::one_point(), &g1_hash, &self.0) } @@ -160,7 +160,7 @@ pub fn verify_aggregate_sig( let product = m_pk_pairs .par_iter() .fold(::one, |prod, (m, pk)| { - let g1_hash = P::G1::hash_to_group(m); + let g1_hash = P::G1::hash_to_group(m).expect("Hashing to curve expected to succeed"); let paired = P::pair(&g1_hash, &pk.0); let mut p = prod; p.mul_assign(&paired); @@ -211,7 +211,7 @@ pub fn verify_aggregate_sig_hybrid( .fold(P::G2::zero_point, |s, x| s.plus_point(&x.0)) .reduce(P::G2::zero_point, |s, x| s.plus_point(&x)) }; - let g1_hash = P::G1::hash_to_group(m); + let g1_hash = P::G1::hash_to_group(m).expect("Hashing to curve expected to succeed"); let paired = P::pair(&g1_hash, &sum_pk_i); let mut p = prod; p.mul_assign(&paired); @@ -255,7 +255,7 @@ pub fn verify_aggregate_sig_trusted_keys( P::check_pairing_eq( &signature.0, &P::G2::one_point(), - &P::G1::hash_to_group(m), + &P::G1::hash_to_group(m).expect("Hashing to curve expected to succeed"), &sum, ) } @@ -281,13 +281,14 @@ fn hash_message(m: &[u8]) -> Output { Sha512::digest(m) } #[cfg(test)] mod test { use super::*; - use pairing::bls12_381::Bls12; use rand::{rngs::StdRng, thread_rng, SeedableRng}; use std::convert::TryFrom; const SIGNERS: usize = 500; const TEST_ITERATIONS: usize = 10; + type Bls12 = ark_ec::bls12::Bls12; + // returns a pair of lists (sks, pks), such that sks[i] and pks[i] are // corresponding secret and public key fn get_sks_pks( @@ -438,10 +439,10 @@ mod test { let mut ms: Vec<[u8; 8]> = (0..signers).map(|x| x.to_le_bytes()).collect(); // Make a duplication in the messages - let random_idx1: usize = rng.gen_range(0, SIGNERS); - let mut random_idx2: usize = rng.gen_range(0, SIGNERS); + let random_idx1: usize = rng.gen_range(0..SIGNERS); + let mut random_idx2: usize = rng.gen_range(0..SIGNERS); while random_idx1 == random_idx2 { - random_idx2 = rng.gen_range(0, SIGNERS) + random_idx2 = rng.gen_range(0..SIGNERS) } ms[random_idx1] = ms[random_idx2]; let vs: Vec<(&[u8], ())> = ms.iter().map(|x| (&x[..], ())).collect(); diff --git a/rust-src/concordium_base/src/base.rs b/rust-src/concordium_base/src/base.rs index 93c313f9b..2fb8bc6e8 100644 --- a/rust-src/concordium_base/src/base.rs +++ b/rust-src/concordium_base/src/base.rs @@ -21,6 +21,7 @@ pub use concordium_contracts_common::{ ZeroSignatureThreshold, }; use derive_more::{Add, Display, From, FromStr, Into, Sub}; +use ed25519_dalek::Signer; use rand::{CryptoRng, Rng}; use std::{ convert::{TryFrom, TryInto}, @@ -613,7 +614,7 @@ impl BakerSignatureSignKey { /// Generate a fresh key using the provided random number generator. pub fn generate(csprng: &mut T) -> Self { Self { - sign_key: ed25519_dalek::SecretKey::generate(csprng), + sign_key: csprng.gen(), } } } @@ -622,13 +623,13 @@ impl BakerSignatureSignKey { #[derive(SerdeBase16Serialize, Serialize, Clone, Debug, PartialEq, Eq)] /// A public key that corresponds to [`BakerSignatureVerifyKey`]. pub struct BakerSignatureVerifyKey { - pub(crate) verify_key: ed25519_dalek::PublicKey, + pub(crate) verify_key: ed25519_dalek::VerifyingKey, } impl From<&BakerSignatureSignKey> for BakerSignatureVerifyKey { fn from(secret: &BakerSignatureSignKey) -> Self { Self { - verify_key: ed25519_dalek::PublicKey::from(&secret.sign_key), + verify_key: ed25519_dalek::SigningKey::from(&secret.sign_key).verifying_key(), } } } @@ -785,46 +786,82 @@ pub struct UpdatePublicKey { /// A ed25519 keypair. This is available in the `ed25519::dalek` crate, but the /// JSON serialization there is not compatible with what we use, so we redefine /// it there. -#[derive(Debug, SerdeSerialize, SerdeDeserialize)] +#[derive(Debug, SerdeSerialize, SerdeDeserialize, derive_more::AsRef, Clone)] +#[serde( + try_from = "update_key_pair_json::UpdateKeyPair", + into = "update_key_pair_json::UpdateKeyPair" +)] pub struct UpdateKeyPair { - #[serde( - rename = "signKey", - serialize_with = "crate::common::base16_encode", - deserialize_with = "crate::common::base16_decode" - )] - pub secret: ed25519_dalek::SecretKey, - #[serde(flatten)] - pub public: UpdatePublicKey, + inner: ed25519_dalek::SigningKey, } -impl UpdateKeyPair { - /// Generate a fresh key pair using the provided random number generator. - pub fn generate(rng: &mut R) -> Self { - let kp = ed25519_dalek::Keypair::generate(rng); - Self { - secret: kp.secret, - public: UpdatePublicKey { - public: VerifyKey::Ed25519VerifyKey(kp.public), - }, +mod update_key_pair_json { + use crate::id::types::SchemeId; + + use super::*; + /// A ed25519 keypair. This is available in the `ed25519::dalek` crate, but + /// the JSON serialization there is not compatible with what we use, so + /// we redefine it there. + #[derive(Debug, SerdeSerialize, SerdeDeserialize)] + pub struct UpdateKeyPair { + #[serde( + rename = "signKey", + serialize_with = "crate::common::base16_encode_array", + deserialize_with = "crate::common::base16_decode_array" + )] + pub secret: ed25519_dalek::SecretKey, + #[serde( + rename = "verifyKey", + serialize_with = "crate::common::base16_encode", + deserialize_with = "crate::common::base16_decode" + )] + pub public: ed25519_dalek::VerifyingKey, + pub schema: Option, + } + + impl TryFrom for super::UpdateKeyPair { + type Error = ed25519_dalek::SignatureError; + + fn try_from(value: UpdateKeyPair) -> Result { + let inner = ed25519_dalek::SigningKey::from_bytes(&value.secret); + if inner.verifying_key() != value.public { + Err(ed25519_dalek::SignatureError::from_source( + "Public key does not match secret key.", + )) + } else { + Ok(Self { inner }) + } } } - /// Sign the message with the keypair. - pub fn sign(&self, msg: &[u8]) -> Signature { - let expanded = ed25519_dalek::ExpandedSecretKey::from(&self.secret); - match self.public.public { - VerifyKey::Ed25519VerifyKey(vf) => { - let sig = expanded.sign(msg, &vf); - Signature { - sig: sig.to_bytes().to_vec(), - } + impl From for UpdateKeyPair { + fn from(value: super::UpdateKeyPair) -> Self { + Self { + secret: value.inner.to_bytes(), + public: value.inner.verifying_key(), + schema: Some(SchemeId::Ed25519), } } } } +impl UpdateKeyPair { + /// Generate a fresh key pair using the provided random number generator. + pub fn generate(rng: &mut R) -> Self { + let inner = ed25519_dalek::SigningKey::generate(rng); + Self { inner } + } + + /// Sign the message with the keypair. + pub fn sign(&self, msg: &[u8]) -> Signature { self.inner.sign(msg).into() } +} + impl From<&UpdateKeyPair> for UpdatePublicKey { - fn from(kp: &UpdateKeyPair) -> Self { kp.public.clone() } + fn from(kp: &UpdateKeyPair) -> Self { + UpdatePublicKey { + public: kp.inner.verifying_key().into(), + } + } } #[derive(Debug, Clone, Copy, SerdeSerialize, SerdeDeserialize, Serialize, Into, Display)] diff --git a/rust-src/concordium_base/src/bulletproofs/inner_product_proof.rs b/rust-src/concordium_base/src/bulletproofs/inner_product_proof.rs index 7addcb249..9163c7e2c 100644 --- a/rust-src/concordium_base/src/bulletproofs/inner_product_proof.rs +++ b/rust-src/concordium_base/src/bulletproofs/inner_product_proof.rs @@ -458,11 +458,12 @@ pub fn inner_product(a: &[F], b: &[F]) -> F { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use crate::curve_arithmetic::Curve; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; use rand::thread_rng; - type SomeCurve = G1; + type SomeCurve = ArkGroup; #[test] fn testinner() { diff --git a/rust-src/concordium_base/src/bulletproofs/range_proof.rs b/rust-src/concordium_base/src/bulletproofs/range_proof.rs index b45a3ebf0..7ed0239d2 100644 --- a/rust-src/concordium_base/src/bulletproofs/range_proof.rs +++ b/rust-src/concordium_base/src/bulletproofs/range_proof.rs @@ -797,15 +797,18 @@ pub fn verify_in_range( #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; /// This function produces a proof that will satisfy the verifier's first /// check, even if the values are not in the interval. /// The second check will fail. /// This is tested by checking if the verifier returns /// Err(Err(VerificationError::Second)) - type SomeCurve = G1; + + type SomeCurve = ArkGroup; + #[allow(non_snake_case)] #[allow(clippy::too_many_arguments)] #[allow(clippy::many_single_char_names)] diff --git a/rust-src/concordium_base/src/bulletproofs/set_membership_proof.rs b/rust-src/concordium_base/src/bulletproofs/set_membership_proof.rs index 8b32c184b..e37277134 100644 --- a/rust-src/concordium_base/src/bulletproofs/set_membership_proof.rs +++ b/rust-src/concordium_base/src/bulletproofs/set_membership_proof.rs @@ -563,9 +563,12 @@ pub fn verify( #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; - type SomeCurve = G1; + use ark_bls12_381::G1Projective; + + type SomeCurve = ArkGroup; /// Converts the u64 set vector into a vector over the field fn get_set_vector(the_set: &[u64]) -> Vec { @@ -573,7 +576,13 @@ mod tests { } /// generates several values used in tests - fn generate_helper_values(n: usize) -> (Generators, CommitmentKey, Randomness) { + fn generate_helper_values( + n: usize, + ) -> ( + Generators, + CommitmentKey, + Randomness, + ) { let rng = &mut thread_rng(); let gens = Generators::generate(n, rng); let b = SomeCurve::generate(rng); @@ -587,9 +596,9 @@ mod tests { /// Generates commitment to v given commitment key and randomness fn get_v_com( v: &::Scalar, - v_keys: &CommitmentKey, - v_rand: &Randomness, - ) -> Commitment { + v_keys: &CommitmentKey, + v_rand: &Randomness, + ) -> Commitment { let v_value = Value::::new(*v); v_keys.hide(&v_value, &v_rand) diff --git a/rust-src/concordium_base/src/bulletproofs/set_non_membership_proof.rs b/rust-src/concordium_base/src/bulletproofs/set_non_membership_proof.rs index 251f9f54e..fb89af25e 100644 --- a/rust-src/concordium_base/src/bulletproofs/set_non_membership_proof.rs +++ b/rust-src/concordium_base/src/bulletproofs/set_non_membership_proof.rs @@ -493,9 +493,12 @@ pub fn verify( #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; - type SomeCurve = G1; + use ark_bls12_381::G1Projective; + + type SomeCurve = ArkGroup; /// Converts the u64 set vector into a vector over the field fn get_set_vector(the_set: &[u64]) -> Vec { @@ -503,7 +506,13 @@ mod tests { } /// generates several values used in tests - fn generate_helper_values(n: usize) -> (Generators, CommitmentKey, Randomness) { + fn generate_helper_values( + n: usize, + ) -> ( + Generators, + CommitmentKey, + Randomness, + ) { let rng = &mut thread_rng(); let gens = Generators::generate(n, rng); let b = SomeCurve::generate(rng); @@ -517,9 +526,9 @@ mod tests { /// Generates commitment to v given commitment key and randomness fn get_v_com( v: &::Scalar, - v_keys: &CommitmentKey, - v_rand: &Randomness, - ) -> Commitment { + v_keys: &CommitmentKey, + v_rand: &Randomness, + ) -> Commitment { let v_value = Value::::new(*v); v_keys.hide(&v_value, &v_rand) diff --git a/rust-src/concordium_base/src/bulletproofs/utils.rs b/rust-src/concordium_base/src/bulletproofs/utils.rs index 25d6125f2..851c5b726 100644 --- a/rust-src/concordium_base/src/bulletproofs/utils.rs +++ b/rust-src/concordium_base/src/bulletproofs/utils.rs @@ -75,11 +75,12 @@ pub(crate) fn pad_vector_to_power_of_two(vec: &mut Vec) { #[cfg(test)] mod tests { + use crate::curve_arithmetic::{arkworks_instances::ArkField, Field}; + use super::{pad_vector_to_power_of_two, z_vec}; - use ff::Field; use rand::thread_rng; - type SomeField = pairing::bls12_381::Fq; + type SomeField = ArkField; #[test] fn test_vector_padding() { diff --git a/rust-src/concordium_base/src/cis2_types.rs b/rust-src/concordium_base/src/cis2_types.rs index 715333ab0..faae88c47 100644 --- a/rust-src/concordium_base/src/cis2_types.rs +++ b/rust-src/concordium_base/src/cis2_types.rs @@ -1125,7 +1125,10 @@ mod test { #[test] fn test_serialize_random_token_amount() { - let seed = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let seed = [ + 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, + ]; let mut rng = SmallRng::from_seed(seed); for n in (0..1000).map(|_| rng.next_u64()) { @@ -1146,7 +1149,10 @@ mod test { "Incorrect amount parse." ); - let seed = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let seed = [ + 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, + ]; let mut rng = SmallRng::from_seed(seed); for n in (0..1000).map(|_| rng.next_u64()) { diff --git a/rust-src/concordium_base/src/common/impls.rs b/rust-src/concordium_base/src/common/impls.rs index 935c59e2a..efc867c42 100644 --- a/rust-src/concordium_base/src/common/impls.rs +++ b/rust-src/concordium_base/src/common/impls.rs @@ -2,11 +2,6 @@ use anyhow::bail; use byteorder::ReadBytesExt; use concordium_contracts_common::{constants::SHA256, hashes::HashBytes, NonZeroThresholdU8}; -use ff::PrimeField; -use group::{CurveAffine, CurveProjective, EncodedPoint}; -use pairing::bls12_381::{ - Fq12, FqRepr, Fr, FrRepr, G1Affine, G1Compressed, G2Affine, G2Compressed, G1, G2, -}; use std::convert::TryFrom; use super::serialize::*; @@ -22,181 +17,34 @@ impl Deserial for concordium_contracts_common::Timestamp { } } -impl Deserial for Fr { - fn deserial(source: &mut R) -> ParseResult { - let mut frrepr: FrRepr = FrRepr([0u64; 4]); - // Read the scalar in big endian. - for digit in frrepr.as_mut().iter_mut().rev() { - *digit = source.get()?; - } - Ok(Fr::from_repr(frrepr)?) - } -} - -impl Serial for Fr { - fn serial(&self, out: &mut B) { - let frpr = &self.into_repr(); - for a in frpr.as_ref().iter().rev() { - a.serial(out); - } - } -} - -impl Deserial for G1 { - fn deserial(source: &mut R) -> ParseResult { - let mut g = G1Compressed::empty(); - source.read_exact(g.as_mut())?; - Ok(g.into_affine()?.into_projective()) - } -} - -impl Serial for G1 { - fn serial(&self, out: &mut B) { - let g = self.into_affine().into_compressed(); - let g_bytes = g.as_ref(); - if let Err(e) = out.write_all(g_bytes) { - panic!( - "Precondition violated. Buffer should be safe to write {}.", - e - ); - } - } -} - -impl Deserial for G1Affine { - fn deserial(source: &mut R) -> ParseResult { - let mut g = G1Compressed::empty(); - source.read_exact(g.as_mut())?; - Ok(g.into_affine()?) - } -} - -impl Serial for G1Affine { - fn serial(&self, out: &mut B) { - let g = self.into_compressed(); - let g_bytes = g.as_ref(); - if let Err(e) = out.write_all(g_bytes) { - panic!( - "Precondition violated. Buffer should be safe to write {}.", - e - ); - } - } -} - -impl Deserial for G2 { - fn deserial(source: &mut R) -> ParseResult { - let mut g = G2Compressed::empty(); - source.read_exact(g.as_mut())?; - Ok(g.into_affine()?.into_projective()) - } -} - -impl Serial for G2 { - fn serial(&self, out: &mut B) { - let g = self.into_affine().into_compressed(); - let g_bytes = g.as_ref(); - if let Err(e) = out.write_all(g_bytes) { - panic!( - "Precondition violated. Buffer should be safe to write {}.", - e - ); - } - } -} - -impl Deserial for G2Affine { - fn deserial(source: &mut R) -> ParseResult { - let mut g = G2Compressed::empty(); - source.read_exact(g.as_mut())?; - Ok(g.into_affine()?) - } -} - -impl Serial for G2Affine { - fn serial(&self, out: &mut B) { - let g = self.into_compressed(); - let g_bytes = g.as_ref(); - if let Err(e) = out.write_all(g_bytes) { - panic!( - "Precondition violated. Buffer should be safe to write {}.", - e - ); - } - } -} - -/// This implementation is ad-hoc, using the fact that Fq12 is defined -/// via that specific tower of extensions (of degrees) 2 -> 3 -> 2, -/// and the specific representation of those fields. -/// We use big-endian representation all the way down to the field Fq. -impl Serial for Fq12 { - fn serial(&self, out: &mut B) { - // coefficients in the extension F_6 - let c0_6 = self.c0; - let c1_6 = self.c1; - - let coeffs = [ - // coefficients of c1_6 in the extension F_2 - c1_6.c2, c1_6.c1, c1_6.c0, // coefficients of c0_6 in the extension F_2 - c0_6.c2, c0_6.c1, c0_6.c0, - ]; - for p in coeffs.iter() { - let repr_c1 = FqRepr::from(p.c1); - let repr_c0 = FqRepr::from(p.c0); - for d in repr_c1.as_ref().iter() { - d.serial(out); - } - for d in repr_c0.as_ref().iter() { - d.serial(out); - } - } - } -} - // Implementations for the dalek curve. use ed25519_dalek::*; -impl Deserial for PublicKey { +impl Deserial for VerifyingKey { fn deserial(source: &mut R) -> ParseResult { let mut buf = [0u8; PUBLIC_KEY_LENGTH]; source.read_exact(&mut buf)?; - Ok(PublicKey::from_bytes(&buf)?) - } -} - -impl Serial for PublicKey { - fn serial(&self, out: &mut B) { - out.write_all(self.as_bytes()) - .expect("Writing to buffer should succeed."); - } -} - -impl Deserial for SecretKey { - fn deserial(source: &mut R) -> ParseResult { - let mut buf = [0u8; SECRET_KEY_LENGTH]; - source.read_exact(&mut buf)?; - Ok(SecretKey::from_bytes(&buf)?) + Ok(VerifyingKey::from_bytes(&buf)?) } } -impl Serial for SecretKey { +impl Serial for VerifyingKey { fn serial(&self, out: &mut B) { out.write_all(self.as_bytes()) .expect("Writing to buffer should succeed."); } } -impl Deserial for Keypair { +impl Deserial for SigningKey { fn deserial(source: &mut R) -> ParseResult { let mut buf = [0u8; KEYPAIR_LENGTH]; source.read_exact(&mut buf)?; - Ok(Keypair::from_bytes(&buf)?) + Ok(SigningKey::from_keypair_bytes(&buf)?) } } -impl Serial for Keypair { +impl Serial for SigningKey { fn serial(&self, out: &mut B) { out.write_all(&self.to_bytes()) .expect("Writing to buffer should succeed."); diff --git a/rust-src/concordium_base/src/common/serialize.rs b/rust-src/concordium_base/src/common/serialize.rs index a64eca48c..93a1d78b0 100644 --- a/rust-src/concordium_base/src/common/serialize.rs +++ b/rust-src/concordium_base/src/common/serialize.rs @@ -877,6 +877,41 @@ pub fn base16_decode<'de, D: Deserializer<'de>, T: Deserial>(des: D) -> Result( + v: &[u8; N], + ser: S, +) -> Result { + let b16_str = encode(v); + ser.serialize_str(&b16_str) +} + +/// Dual to [`base16_encode_array`]. More efficient than [`base16_decode`] since +/// it reads the entire byte array in one chunk. +pub(crate) fn base16_decode_array<'de, D: Deserializer<'de>, const N: usize>( + des: D, +) -> Result<[u8; N], D::Error> { + struct Base16Visitor(std::marker::PhantomData<[u8; N]>); + + impl<'de, const N: usize> Visitor<'de> for Base16Visitor { + type Value = [u8; N]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "A base 16 string.") + } + + fn visit_str(self, v: &str) -> Result { + let bytes = decode(v).map_err(de::Error::custom)?; + bytes + .try_into() + .map_err(|_| de::Error::custom("Unexpected array length.")) + } + } + + des.deserialize_str(Base16Visitor(Default::default())) +} + /// Analogous to [base16_encode], but encodes into a string rather than a serde /// Serializer. pub fn base16_encode_string(x: &S) -> String { encode(to_bytes(x)) } @@ -963,7 +998,7 @@ fn test_set_serialization() { fn test_string_serialization() { use rand::Rng; for _ in 0..1000 { - let n: usize = rand::thread_rng().gen_range(0, 2 * MAX_PREALLOCATED_CAPACITY); + let n: usize = rand::thread_rng().gen_range(0..2 * MAX_PREALLOCATED_CAPACITY); let s: String = String::from_utf8(vec!['a' as u8; n]).unwrap(); let deserialized = super::serialize_deserialize(&s).expect("Deserialization succeeds."); assert_eq!(s, deserialized); diff --git a/rust-src/concordium_base/src/common/types.rs b/rust-src/concordium_base/src/common/types.rs index bd6416f08..2ceeb6ffa 100644 --- a/rust-src/concordium_base/src/common/types.rs +++ b/rust-src/concordium_base/src/common/types.rs @@ -14,6 +14,7 @@ pub use concordium_contracts_common::{ AccountAddress, Address, Amount, Timestamp, ACCOUNT_ADDRESS_SIZE, }; use derive_more::{Display, From, FromStr, Into}; +use ed25519_dalek::Signer; use std::{collections::BTreeMap, num::ParseIntError, str::FromStr}; /// Index of an account key that is to be used. #[derive( @@ -310,6 +311,14 @@ pub struct Signature { pub sig: Vec, } +impl From for Signature { + fn from(value: ed25519_dalek::Signature) -> Self { + Self { + sig: value.to_vec(), + } + } +} + impl Serial for Signature { fn serial(&self, out: &mut B) { (self.sig.len() as u16).serial(out); @@ -450,55 +459,73 @@ impl FromStr for TransactionTime { /// A ed25519 keypair. This is available in the `ed25519::dalek` crate, but the /// JSON serialization there is not compatible with what we use, so we redefine /// it there. -#[derive(Debug, SerdeSerialize, SerdeDeserialize)] +#[derive( + Debug, + SerdeSerialize, + SerdeDeserialize, + derive_more::AsRef, + derive_more::From, + derive_more::Into, + Clone, +)] +#[serde(try_from = "key_pair_json::KeyPair", into = "key_pair_json::KeyPair")] pub struct KeyPair { - #[serde( - rename = "signKey", - serialize_with = "crate::common::base16_encode", - deserialize_with = "crate::common::base16_decode" - )] - pub secret: ed25519_dalek::SecretKey, - #[serde( - rename = "verifyKey", - serialize_with = "crate::common::base16_encode", - deserialize_with = "crate::common::base16_decode" - )] - pub public: ed25519_dalek::PublicKey, + inner: ed25519_dalek::SigningKey, } impl KeyPair { - pub fn generate(rng: &mut R) -> Self { - Self::from(ed25519_dalek::Keypair::generate(rng)) + pub fn public(&self) -> ed25519_dalek::VerifyingKey { self.inner.verifying_key() } +} + +mod key_pair_json { + #[derive(Debug, super::SerdeSerialize, super::SerdeDeserialize)] + pub struct KeyPair { + #[serde( + rename = "signKey", + serialize_with = "crate::common::base16_encode_array", + deserialize_with = "crate::common::base16_decode_array" + )] + pub secret: ed25519_dalek::SecretKey, + #[serde( + rename = "verifyKey", + serialize_with = "crate::common::base16_encode", + deserialize_with = "crate::common::base16_decode" + )] + pub public: ed25519_dalek::VerifyingKey, + } + + impl TryFrom for super::KeyPair { + type Error = ed25519_dalek::SignatureError; + + fn try_from(value: KeyPair) -> Result { + let inner = ed25519_dalek::SigningKey::from_bytes(&value.secret); + if inner.verifying_key() != value.public { + Err(Self::Error::from_source("Public/secret key mismatch.")) + } else { + Ok(Self { inner }) + } + } } -} -impl From for KeyPair { - fn from(kp: ed25519_dalek::Keypair) -> Self { - Self { - secret: kp.secret, - public: kp.public, + impl From for KeyPair { + fn from(value: super::KeyPair) -> Self { + Self { + secret: value.inner.to_bytes(), + public: value.inner.verifying_key(), + } } } } impl KeyPair { - /// Sign the given message with the keypair. - pub fn sign(&self, msg: &[u8]) -> Signature { - let expanded = ed25519_dalek::ExpandedSecretKey::from(&self.secret); - let sig = expanded.sign(msg, &self.public); - Signature { - sig: sig.to_bytes().to_vec(), - } + pub fn generate(rng: &mut R) -> Self { + Self::from(ed25519_dalek::SigningKey::generate(rng)) } } -impl From for ed25519_dalek::Keypair { - fn from(kp: KeyPair) -> ed25519_dalek::Keypair { - ed25519_dalek::Keypair { - secret: kp.secret, - public: kp.public, - } - } +impl KeyPair { + /// Sign the given message with the keypair. + pub fn sign(&self, msg: &[u8]) -> ed25519_dalek::Signature { self.inner.sign(msg) } } #[cfg(test)] @@ -513,16 +540,16 @@ mod tests { fn transaction_signature_serialization() { let mut rng = rand::thread_rng(); for _ in 0..100 { - let num_creds = rng.gen_range(1, 30); + let num_creds = rng.gen_range(1..30); let mut signatures = BTreeMap::new(); for _ in 0..num_creds { - let num_keys = rng.gen_range(1, 20); + let num_keys = rng.gen_range(1..20); let mut cred_sigs = BTreeMap::new(); for _ in 0..num_keys { - let num_elems = rng.gen_range(0, 200); + let num_elems = rng.gen_range(0..200); let sig = Signature { sig: Uniform::new_inclusive(0, 255u8) - .sample_iter(rng) + .sample_iter(rng.clone()) .take(num_elems) .collect(), }; diff --git a/rust-src/concordium_base/src/curve_arithmetic/arkworks_instances.rs b/rust-src/concordium_base/src/curve_arithmetic/arkworks_instances.rs new file mode 100644 index 000000000..093f4a97d --- /dev/null +++ b/rust-src/concordium_base/src/curve_arithmetic/arkworks_instances.rs @@ -0,0 +1,209 @@ +//! Wrapper types and blanket implementations serving as adapters from +//! `arkworks` field/curve traits. +use super::{Curve, CurveDecodingError, Field, GenericMultiExp, PrimeField}; +use crate::common::{Deserial, Serial, Serialize}; +use ark_ec::hashing::{HashToCurve, HashToCurveError}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use core::fmt; + +/// A wrapper type for `arkworks` field types. +#[derive( + PartialOrd, Ord, PartialEq, Eq, Copy, Clone, fmt::Debug, derive_more::From, derive_more::FromStr, +)] +pub struct ArkField(pub(crate) F); + +/// Serialization is implemented by delegating the functionality to the wrapped +/// type. +impl Serial for ArkField { + fn serial(&self, out: &mut B) { self.0.serial(out) } +} + +/// Deserialization is implemented by delegating the functionality to the +/// wrapped type. +impl Deserial for ArkField { + fn deserial(source: &mut R) -> crate::common::ParseResult { + let res = F::deserial(source)?; + Ok(res.into()) + } +} + +/// A blanket implementation of the `Field` trait using the functionality of +/// `ark_ff::Field`. This gives an implementation of our `Field` trait for +/// `ArkField` for any `F` that implements `ark_ff::Field`. +impl Field for ArkField { + fn random(rng: &mut R) -> Self { + F::rand(rng).into() + } + + fn zero() -> Self { F::zero().into() } + + fn one() -> Self { F::one().into() } + + fn is_zero(&self) -> bool { F::is_zero(&self.0) } + + fn square(&mut self) { self.0.square_in_place(); } + + fn double(&mut self) { self.0.double_in_place(); } + + fn negate(&mut self) { self.0.neg_in_place(); } + + fn add_assign(&mut self, other: &Self) { self.0 += other.0 } + + fn sub_assign(&mut self, other: &Self) { self.0 -= other.0 } + + fn mul_assign(&mut self, other: &Self) { self.0 *= other.0 } + + fn inverse(&self) -> Option { self.0.inverse().map(|x| x.into()) } +} + +impl ArkField { + pub fn into_ark(&self) -> &F { &self.0 } +} + +/// A blanket implementation of the `PrimeField` trait using the functionality +/// of `ark_ff::PrimeField`. This gives an implementation of our `PrimeField` +/// trait for `ArkField` for any `F` that implements `ark_ff::PrimeField`. +impl PrimeField for ArkField { + const CAPACITY: u32 = Self::NUM_BITS - 1; + const NUM_BITS: u32 = F::MODULUS_BIT_SIZE; + + fn into_repr(self) -> Vec { self.0.into_bigint().as_ref().to_vec() } + + fn from_repr(repr: &[u64]) -> Result { + let mut buffer = Vec::with_capacity(8 * repr.len()); + + for u in repr { + buffer.extend(u.to_le_bytes()); + } + + let big_int = num_bigint::BigUint::from_bytes_le(&buffer) + .try_into() + .map_err(|_| CurveDecodingError::NotInField(format!("{:?}", repr)))?; + + let res = + F::from_bigint(big_int).ok_or(CurveDecodingError::NotInField(format!("{:?}", repr)))?; + + Ok(res.into()) + } +} + +/// A wrapper type for `arkworks` group types. +#[derive(PartialEq, Eq, Copy, Clone, fmt::Debug, derive_more::From)] +pub struct ArkGroup(pub(crate) G); + +impl ArkGroup { + pub fn into_ark(&self) -> &G { &self.0 } +} + +/// Serialization is implemented by delegating the functionality to the +/// compressed affine representation of `ark_ec:CurveGroup`. +impl Serial for ArkGroup { + fn serial(&self, out: &mut B) { + self.0 + .into_affine() + .serialize_compressed(out) + .expect("Serialization expected to succeed"); + } +} + +/// Deserialization is implemented by delegating the functionality to the +/// compressed affine representation of `ark_ec:CurveGroup`. +impl Deserial for ArkGroup { + fn deserial(source: &mut R) -> crate::common::ParseResult { + let res = G::Affine::deserialize_compressed(source)?; + Ok(ArkGroup(res.into())) + } +} + +impl From for CurveDecodingError { + fn from(_value: HashToCurveError) -> Self { CurveDecodingError::NotOnCurve } +} + +/// Curve configuration. +/// +/// These parameters cannot be taken from the `arkworks` traits. Each `arkworks` +/// curve should come with an implementation of this configuration trait. +pub(crate) trait ArkCurveConfig { + /// Size in bytes of elements of the scalar field. + const SCALAR_LENGTH: usize; + /// Size in bytes of group elements when serialized. + const GROUP_ELEMENT_LENGTH: usize; + /// Domain separation string for hashing arbitrary data to a group element + /// on an elliptic curve. + const DOMAIN_STRING: &'static str; + /// A hasher that implements hashing arbitrary data to a group element on an + /// elliptic curve. + type Hasher: ark_ec::hashing::HashToCurve; +} + +/// A blanket implementation of the `Curve` trait using the functionality of +/// `ark_ec::CurveGroup` and curve configuration `ArkCurveConfig`. This gives an +/// implementation of our `Curve` trait for `ArkGroup` for any `F` that +/// implements `ark_ec::CurveGroup`, provided an instance of `ArkCurveConfig` +/// for that curve. +impl> Curve for ArkGroup +where + ::ScalarField: Serialize, +{ + type MultiExpType = GenericMultiExp; + type Scalar = ArkField<::ScalarField>; + + const GROUP_ELEMENT_LENGTH: usize = G::GROUP_ELEMENT_LENGTH; + const SCALAR_LENGTH: usize = G::SCALAR_LENGTH; + + fn zero_point() -> Self { ArkGroup(G::zero()) } + + fn one_point() -> Self { ArkGroup(G::generator()) } + + fn is_zero_point(&self) -> bool { self.0.is_zero() } + + fn inverse_point(&self) -> Self { ArkGroup(-self.0) } + + fn double_point(&self) -> Self { ArkGroup(self.0.double()) } + + fn plus_point(&self, other: &Self) -> Self { ArkGroup(self.0 + other.0) } + + fn minus_point(&self, other: &Self) -> Self { ArkGroup(self.0 - other.0) } + + fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self { ArkGroup(self.0 * scalar.0) } + + fn generate(rng: &mut R) -> Self { ArkGroup(G::rand(rng)) } + + fn generate_scalar(rng: &mut R) -> Self::Scalar { + ::rand(rng).into() + } + + fn scalar_from_u64(n: u64) -> Self::Scalar { ArkField(G::ScalarField::from(n)) } + + fn scalar_from_bytes>(bs: A) -> Self::Scalar { + // Traverse at most `ceil(CAPACITY / 64)` 8-byte chunks. + let num_chunks = num::integer::div_ceil(Self::Scalar::CAPACITY, 64); + let mut fr = vec![0u64; num_chunks as usize]; + for (chunk, place) in bs.as_ref().chunks(8).take(num_chunks as usize).zip(&mut fr) { + let mut v = [0u8; 8]; + v[..chunk.len()].copy_from_slice(chunk); + *place = u64::from_le_bytes(v); + } + let total_size_in_bits = num_chunks * 64; + let num_bits_to_remove = total_size_in_bits - Self::Scalar::CAPACITY; + // create a mask for the last chunk with the topmost `num_bits_to_remove` zeros + // followed by `CAPACITY` of ones; it's implemented using (logical) right shift + // that adds zeros from the left. E.g. if `num_bits_to_remove = 2`, the + // mask will be `00111..11` + let mask = u64::MAX >> num_bits_to_remove; + // unset `num_bits_to_remove` topmost bits in the last u64. + *fr.last_mut().expect("Non empty vector expected") &= mask; + ::from_repr(&fr).unwrap_or_else(|_| { + panic!( + "The scalar {:?} with top {:} bits erased should be valid.", + fr, num_bits_to_remove + ) + }) + } + + fn hash_to_group(m: &[u8]) -> Result { + let hasher = G::Hasher::new(G::DOMAIN_STRING.as_ref())?; + let res = G::Hasher::hash(&hasher, m)?; + Ok(ArkGroup(res.into())) + } +} diff --git a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_arkworks.rs b/rust-src/concordium_base/src/curve_arithmetic/bls12_381_arkworks.rs new file mode 100644 index 000000000..165ce71b1 --- /dev/null +++ b/rust-src/concordium_base/src/curve_arithmetic/bls12_381_arkworks.rs @@ -0,0 +1,691 @@ +//! Trait implementations for the BLS12-381 curve from `arkworks`. +//! Include configuration for `G1` and `G2`, `Pairing`, and serialization for +//! the target group elements. +use core::fmt; + +use ark_bls12_381::*; +use ark_ec::{ + hashing::{curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurveBasedHasher}, + pairing::MillerLoopOutput, + short_weierstrass::Projective, + CurveGroup, +}; +use ark_ff::{field_hashers::DefaultFieldHasher, BigInt, PrimeField}; +use byteorder::ReadBytesExt; +use num_bigint::BigUint; +use sha2::Sha256; + +use crate::common::{Buffer, Deserial, ParseResult, Serial}; + +use anyhow::anyhow; + +use super::{ + arkworks_instances::{ArkCurveConfig, ArkField, ArkGroup}, + Pairing, +}; + +impl ArkCurveConfig for Projective { + type Hasher = MapToCurveBasedHasher< + Projective, + DefaultFieldHasher, + WBMap, + >; + + const DOMAIN_STRING: &'static str = "CONCORDIUM-hashtoG1-with-BLS12381G1_XMD:SHA-256_SSWU_RO"; + const GROUP_ELEMENT_LENGTH: usize = 48; + const SCALAR_LENGTH: usize = 32; +} + +impl ArkCurveConfig for Projective { + type Hasher = + MapToCurveBasedHasher, WBMap>; + + const DOMAIN_STRING: &'static str = "CONCORDIUM-hashtoG2-with-BLS12381G2_XMD:SHA-256_SSWU_RO"; + const GROUP_ELEMENT_LENGTH: usize = 96; + const SCALAR_LENGTH: usize = 32; +} + +impl Deserial for Fr { + fn deserial(source: &mut R) -> ParseResult { + let mut buf = [0u8; 32]; + source.read_exact(&mut buf)?; + // Construct the scalar from big endian bytes. + let big_int: BigInt<4> = BigUint::from_bytes_be(&buf) + .try_into() + .map_err(|_| anyhow!("Cannot convert to bigint"))?; + let res = Fr::from_bigint(big_int) + .ok_or(anyhow!("Cannot convert from bigint to a field element"))?; + Ok(res) + } +} + +impl Serial for Fr { + fn serial(&self, out: &mut B) { + // Note that it is crucial to use `into_bigint()` here. + // The internal representation is accessible directly, but it's NOT the same. + // The representation depends on the selected backend. + // By default, it's a Montgomery representation optimized for modular + // arithmetic. + let frpr = self.into_bigint(); + for a in frpr.0.iter().rev() { + a.serial(out); + } + } +} + +/// This implementation is ad-hoc, using the fact that Fq12 is defined +/// via that specific tower of extensions (of degrees) 2 -> 3 -> 2, +/// and the specific representation of those fields. +/// We use big-endian representation all the way down to the field Fq. +impl Serial for Fq12 { + fn serial(&self, out: &mut B) { + // coefficients in the extension F_6 + let c0_6 = self.c0; + let c1_6 = self.c1; + + let coeffs = [ + // coefficients of c1_6 in the extension F_2 + c1_6.c2, c1_6.c1, c1_6.c0, // coefficients of c0_6 in the extension F_2 + c0_6.c2, c0_6.c1, c0_6.c0, + ]; + for p in coeffs.iter() { + let repr_c1: BigInt<6> = p.c1.into_bigint(); + let repr_c0: BigInt<6> = p.c0.into_bigint(); + for d in repr_c1.0.iter() { + d.serial(out); + } + for d in repr_c0.0.iter() { + d.serial(out); + } + } + } +} + +type Bls12 = ark_ec::bls12::Bls12; + +impl Pairing for Bls12 { + type G1 = ArkGroup<::G1>; + type G1Prepared = ::G1Prepared; + type G2 = ArkGroup<::G2>; + type G2Prepared = ::G2Prepared; + type ScalarField = ArkField; + type TargetField = ArkField<::TargetField>; + + #[inline(always)] + fn g1_prepare(g: &Self::G1) -> Self::G1Prepared { g.into_ark().into_affine().into() } + + #[inline(always)] + fn g2_prepare(g: &Self::G2) -> Self::G2Prepared { g.into_ark().into_affine().into() } + + #[inline(always)] + fn miller_loop<'a, I>(i: I) -> Self::TargetField + where + I: IntoIterator, { + let (xs, ys): (Vec<_>, Vec<_>) = i.into_iter().copied().unzip(); + let res = ::multi_miller_loop( + xs.into_iter().cloned(), + ys.into_iter().cloned(), + ) + .0; + res.into() + } + + #[inline(always)] + fn final_exponentiation(x: &Self::TargetField) -> Option { + let res = ::final_exponentiation(MillerLoopOutput(x.0)); + res.map(|x| x.0.into()) + } + + #[inline(always)] + fn generate_scalar(csprng: &mut T) -> Self::ScalarField { + ::rand(csprng).into() + } +} + +impl fmt::Display for ArkField { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x")?; + for i in self.0.into_bigint().0.iter().rev() { + write!(f, "{:016x}", *i)?; + } + Ok(()) + } +} + +/// Tess for serialization/deserialization and conversion to/from bigint +/// representation. +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + common::*, + curve_arithmetic::{Curve, Field, PrimeField}, + }; + use num_bigint::BigUint; + use rand::{thread_rng, Rng, RngCore}; + + type G1 = ArkGroup; + type G2 = ArkGroup; + + const SCALAR_BYTES_LE: [u8; 32] = [ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 0, + 0, 0, 0, 0, 0, 0, 0, + ]; + + const SCALAR_BYTES_LE_SHORT: [u8; 30] = [ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 0, + 0, 0, 0, 0, 255, + ]; + + const SCALAR_BYTES_LE_LONG: [u8; 33] = [ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 0, + 0, 0, 0, 0, 0, 0, 0, 255, + ]; + + /// Test that if the size of the input array to `scalar_from_bytes()` is + /// less than 32, extra zeros are added at the end of the array to extend it + /// to 32 bytes. + #[test] + fn scalar_from_bytes_short() { + let s = ::scalar_from_bytes(&SCALAR_BYTES_LE_SHORT); + let limbs: Vec = s.into_repr(); + // Convert limbs into an array of bytes + let mut buffer = Vec::with_capacity(32); + for u in limbs { + buffer.extend(u.to_le_bytes()); + } + let bytes: [u8; 32] = buffer + .try_into() + .expect("Expected a bytes array of size 32"); + let mut expected = [0u8; 32]; + // fill the fist bytes with the input, remainig bytes will be zeroes. + expected[..30].copy_from_slice(&SCALAR_BYTES_LE_SHORT); + assert_eq!(expected, bytes) + } + + /// Test that if the size of the input array to `scalar_from_bytes()` is + /// greater than 32, the extra bytes are ignored. + #[test] + fn scalar_from_bytes_long() { + let s = ::scalar_from_bytes(&SCALAR_BYTES_LE_LONG); + let fits_capacity_limbs: Vec = s.into_repr(); + // Create four u64 limbs of the scalar representation from the first 32 bytes + let mut limbs_from_long = [0u64; 4]; + let mut buffer = [0u8; 32]; + buffer.copy_from_slice(&SCALAR_BYTES_LE_LONG[..32]); + for (i, chunk) in buffer.as_ref().chunks(8).take(4).enumerate() { + let mut v = [0u8; 8]; + v[..chunk.len()].copy_from_slice(chunk); + limbs_from_long[i] = u64::from_le_bytes(v); + } + compare_up_to_last_two_bits(&limbs_from_long, &fits_capacity_limbs) + } + + /// Compare the limbs masking the last limb of the first argument. + /// The second agument is assumed to be obtained from `scalar_from_bytes`, + /// so it is always capped by CAPACITY + fn compare_up_to_last_two_bits(limbs: &[u64], fits_capacity_limbs: &[u64]) { + let mask = !(1u64 << 63 | 1u64 << 62); + assert_eq!(limbs[0], fits_capacity_limbs[0], "First limb."); + assert_eq!(limbs[1], fits_capacity_limbs[1], "Second limb."); + assert_eq!(limbs[2], fits_capacity_limbs[2], "Third limb."); + assert_eq!( + limbs[3] & mask, + fits_capacity_limbs[3], + "Fourth limb with top bit masked." + ); + } + + /// Check that scalar_from_bytes works on small values. + #[test] + fn scalar_from_bytes_small() { + let mut rng = rand::thread_rng(); + for _ in 0..1000 { + let n = >::random(&mut rng); + let mut bytes = to_bytes(&n); + bytes.reverse(); + let m = ::scalar_from_bytes(&bytes); + // make sure that n and m only differ in the topmost bit. + let n = n.into_repr(); + let m = m.into_repr(); + compare_up_to_last_two_bits(&n, &m); + } + } + + // Test that everything that exeeds `CAPACITY` is ignored + /// by `Curve::scalar_from_bytes()` + #[test] + fn test_scalar_from_bytes_big() { + let mut rng = rand::thread_rng(); + for _ in 0..1000 { + // First, we generate 31 random bytes. + let mut lower_bytes: [u8; 31] = [0u8; 31]; + rng.fill_bytes(&mut lower_bytes); + let mut fits_capacity_bytes = [0u8; 32]; + // Next, we create a byte array that is filled with random lower bytes, the last + // byte is in [0; 63], that is, of the form 0b00XXXXXX (big-endian). + fits_capacity_bytes[0..31].copy_from_slice(&lower_bytes); + let n = rng.gen_range(0..63); + fits_capacity_bytes[31] = n; + let fits_capacity = ::scalar_from_bytes(fits_capacity_bytes); + let i = rng.gen_range(1..4); + // Now, we create a byte array from lower bytes with the last byte being number + // that is guaranteed to exceed `G1::Scalar::CAPACITY`. + let mut bytes: [u8; 32] = [0u8; 32]; + bytes[0..31].copy_from_slice(&lower_bytes); + // Add 0bXX000000 that leaves the first six bits untouched. + bytes[31] = n + (i << 6); + assert!( + bytes[31] > 63, + "The last byte expected to be grater than 63 to exceed CAPACITY" + ); + let over_capacity = ::scalar_from_bytes(bytes); + // Check that two topmost bits are ignored. + assert_eq!(fits_capacity, over_capacity); + } + } + + /// Test that `into_repr()` correctly converts a scalar constructed from a + /// byte array to an array of limbs with least significant digits first. + #[test] + fn test_into() { + let bigint: BigUint = BigUint::from_bytes_le(&SCALAR_BYTES_LE); + let s: ArkField = Fr::try_from(bigint) + .expect("Expected a valid scalar") + .into(); + assert_eq!(s.into_repr(), [1u64, 0u64, u64::MAX - 1, 0u64]); + } + + /// Turn scalar elements into representations and back again, and compare. + #[test] + fn test_into_from_rep() { + let mut csprng = rand::thread_rng(); + for _ in 0..1000 { + let scalar = >::random(&mut csprng); + let scalar_vec64 = scalar.into_repr(); + let scalar_res = >::from_repr(&scalar_vec64); + assert!(scalar_res.is_ok()); + assert_eq!(scalar_vec64.len(), 4); + assert_eq!(scalar, scalar_res.unwrap()); + } + } + + /// Test that the scalar serialization produces big-endian bytes. + #[test] + fn test_scalar_serialize_big_endian() { + let bigint: BigUint = BigUint::from_bytes_le(&SCALAR_BYTES_LE); + let b: BigInt<4> = bigint + .try_into() + .expect("Expeted valid biguint representing a fired element"); + let s: ArkField = ::from_bigint(b) + .expect("Expected a valid scalar") + .into(); + let mut out = Vec::new(); + s.serial(&mut out); + let scalar_bytes_be: Vec = SCALAR_BYTES_LE.into_iter().rev().collect(); + assert_eq!(scalar_bytes_be, out); + } + + /// A macro for testing that serializing a scalar and deserializing it back + /// gives the same scalar. + macro_rules! macro_test_scalar_byte_conversion { + ($function_name:ident, $p:path) => { + #[test] + pub fn $function_name() { + let mut csprng = thread_rng(); + for _ in 0..1000 { + let scalar = <$p>::generate_scalar(&mut csprng); + let scalar_res = serialize_deserialize(&scalar); + assert!(scalar_res.is_ok()); + assert_eq!(scalar, scalar_res.unwrap()); + } + } + }; + } + + /// A macro for testing that serializing a point and deserializing it back + /// gives the same point. + macro_rules! macro_test_group_byte_conversion { + ($function_name:ident, $p:path) => { + #[test] + pub fn $function_name() { + let mut csprng = thread_rng(); + for _ in 0..1000 { + let curve = <$p>::generate(&mut csprng); + let curve_res = serialize_deserialize(&curve); + assert!(curve_res.is_ok()); + assert_eq!(curve, curve_res.unwrap()); + } + } + }; + } + + macro_test_scalar_byte_conversion!(sc_bytes_conv_g1, G1); + macro_test_scalar_byte_conversion!(sc_bytes_conv_g2, G2); + macro_test_scalar_byte_conversion!(sc_bytes_conv_bls12, Bls12); + + macro_test_group_byte_conversion!(curve_bytes_conv_g1, G1); + macro_test_group_byte_conversion!(curve_bytes_conv_g2, G2); +} + +/// Test for hashig arbitrary bytes to curve. The tests were ported from the +/// custom implementation that was replaced with the `arkworks` +/// `MapToCurveBasedHasher` implementation instantiated with the `G1` and `G2` +/// groups on `BLS12-381`. +#[cfg(test)] +mod hash_to_curve_tests { + // Note that that the old custom implementation refers to https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10. + // However, `ark-ec` v.0.4.0 https://docs.rs/ark-ec/0.4.0/src/ark_ec/hashing/map_to_curve_hasher.rs.html#48 refers + // to the previous version of the draft. Both drafts describe the same + // algorithms and use the same test vectors for the BLS curve. Test vectors + // of the v9 of the draft can be found in Appendix H.9.1 https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-09#section-h.9.1 and + // H.10.1 https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-09#section-h.10.1 + + use super::*; + use crate::{common::*, curve_arithmetic::Field}; + use ark_ec::hashing::HashToCurve; + use ark_ff::field_hashers::HashToField; + use num_traits::One; + use std::str::FromStr; + + type G1 = ArkGroup; + type G2 = ArkGroup; + type Fq = ArkField; + + fn hash_to_curve(msg: &[u8], dst: &[u8]) -> G1 { + let hasher = >::Hasher::new(dst) + .expect("Expected valid domain separation string"); + let res = >::Hasher::hash(&hasher, msg) + .expect("Expected successful hashing to curve"); + ArkGroup(res.into()) + } + + fn hash_to_curve_g2(msg: &[u8], dst: &[u8]) -> G2 { + let hasher = >::Hasher::new(dst) + .expect("Expected valid domain separation string"); + let res = >::Hasher::hash(&hasher, msg) + .expect("Expected successful hashing to curve"); + ArkGroup(res.into()) + } + + fn hash_to_field_fq2(msg: &[u8], dst: &[u8]) -> (Fq2, Fq2) { + let hasher = as HashToField>::new(dst); + let fs: Vec = hasher.hash_to_field(msg, 2); + (fs[0], fs[1]) + } + + fn from_coordinates_unchecked(x: Fq, y: Fq, z: Fq) -> G1 { + G1Projective::new_unchecked(x.0, y.0, z.0).into() + } + + fn from_coordinates_unchecked_g2(x: Fq2, y: Fq2, z: Fq2) -> G2 { + G2Projective::new_unchecked(x, y, z).into() + } + + // This tests the function hash_to_curve function according to + // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-J.9.1 with + // suite = BLS12381G1_XMD:SHA-256_SSWU_RO_ + // dst = QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_ + #[test] + fn test_hash_to_curve() { + let msg = "".as_bytes(); + let dst = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_"; + let p = hash_to_curve(msg, &dst[..]); + assert_eq!(to_bytes(&p), vec![ + 133, 41, 38, 173, 210, 32, 123, 118, 202, 79, 165, 122, 135, 52, 65, 108, 141, 201, 94, + 36, 80, 23, 114, 200, 20, 39, 135, 0, 238, 214, 209, 228, 232, 207, 98, 217, 192, 157, + 176, 250, 195, 73, 97, 43, 117, 158, 121, 161 + ]); + // The point should have (in hex) + // P.x = 052926add2207b76ca4fa57a8734416c8dc95e24501772c8142787 + // 00eed6d1e4e8cf62d9c09db0fac349612b759e79a1 + // P.y = 08ba738453bfed09cb546dbb0783dbb3a5f1f566ed67bb6be0e8c6 + // 7e2e81a4cc68ee29813bb7994998f3eae0c9c6a265 + assert_eq!(p, from_coordinates_unchecked( + Fq::from_str("794311575721400831362957049303781044852006323422624111893352859557450008308620925451441746926395141598720928151969").unwrap(), + Fq::from_str("1343412193624222137939591894701031123123641958980729764240763391191550653712890272928110356903136085217047453540965").unwrap(), + Fq::one())); + let msg = "abc".as_bytes(); + let p = hash_to_curve(msg, &dst[..]); + assert_eq!(to_bytes(&p), vec![ + 131, 86, 123, 197, 239, 156, 105, 12, 42, 178, 236, 223, 106, 150, 239, 28, 19, 156, + 192, 178, 242, 132, 220, 160, 169, 167, 148, 51, 136, 164, 154, 58, 238, 102, 75, 165, + 55, 154, 118, 85, 211, 198, 137, 0, 190, 47, 105, 3 + ]); + // The point should have (in hex) + // P.x = 03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a794 + // 3388a49a3aee664ba5379a7655d3c68900be2f6903 + // P.y = 0b9c15f3fe6e5cf4211f346271d7b01c8f3b28be689c8429c85b67 + // af215533311f0b8dfaaa154fa6b88176c229f2885d + assert_eq!(p, from_coordinates_unchecked( + Fq::from_str("513738460217615943921285247703448567647875874745567372796164155472383127756567780059136521508428662765965997467907").unwrap(), + Fq::from_str("1786897908129645780825838873875416513994655004408749907941296449131605892957529391590865627492442562626458913769565").unwrap(), + Fq::one())); + let msg = "abcdef0123456789".as_bytes(); + let p = hash_to_curve(msg, &dst[..]); + assert_eq!(to_bytes(&p), vec![ + 145, 224, 176, 121, 222, 162, 154, 104, 240, 56, 62, 233, 79, 237, 27, 148, 9, 149, 39, + 36, 7, 227, 187, 145, 107, 191, 38, 140, 38, 61, 221, 87, 166, 162, 114, 0, 167, 132, + 203, 194, 72, 232, 79, 53, 124, 232, 45, 152 + ]); + // The point should have (in hex) + // P.x = 11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf26 + // 8c263ddd57a6a27200a784cbc248e84f357ce82d98 + // P.y = 03a87ae2caf14e8ee52e51fa2ed8eefe80f02457004ba4d486d6aa + // 1f517c0889501dc7413753f9599b099ebcbbd2d709 + assert_eq!(p, from_coordinates_unchecked( + Fq::from_str("2751628761372137084683207295437105268166375184027748372156952770986741873369176463286511518644061904904607431667096").unwrap(), + Fq::from_str("563036982304416203921640398061260377444881693369806087719971277317609936727208012968659302318886963927918562170633").unwrap(), + Fq::one())); + let msg = "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq".as_bytes(); + let p = hash_to_curve(msg, &dst[..]); + assert_eq!(to_bytes(&p), vec![ + 181, 246, 142, 170, 105, 59, 149, 204, 184, 82, 21, 220, 101, 250, 129, 3, 141, 105, + 98, 159, 112, 174, 238, 13, 15, 103, 124, 242, 34, 133, 231, 191, 88, 215, 203, 134, + 238, 254, 143, 46, 155, 195, 248, 203, 132, 250, 196, 136 + ]); + // The point should have (in hex) + // P.x = 15f68eaa693b95ccb85215dc65fa81038d69629f70aeee0d0f677c + // f22285e7bf58d7cb86eefe8f2e9bc3f8cb84fac488 + // P.y = 1807a1d50c29f430b8cafc4f8638dfeeadf51211e1602a5f184443 + // 076715f91bb90a48ba1e370edce6ae1062f5e6dd38 + assert_eq!(p, from_coordinates_unchecked( + Fq::from_str("3380432694887674439773082418192083720584748080704959172978586229921475315220434165460350679208315690319508336723080").unwrap(), + Fq::from_str("3698526739072864408749571082270628561764415577445404115596990919801523793138348254443092179877354467167123794222392").unwrap(), + Fq::one())); + let msg = "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes(); + let p = hash_to_curve(msg, &dst[..]); + assert_eq!(to_bytes(&p), vec![ + 136, 42, 171, 174, 139, 125, 237, 176, 231, 138, 235, 97, 154, 211, 191, 217, 39, 122, + 47, 119, 186, 127, 173, 32, 239, 106, 171, 220, 108, 49, 209, 155, 165, 166, 209, 34, + 131, 85, 50, 148, 193, 130, 92, 75, 60, 162, 220, 254 + ]); + // The point should have (in hex) + // P.x = 082aabae8b7dedb0e78aeb619ad3bfd9277a2f77ba7fad20ef6aab + // dc6c31d19ba5a6d12283553294c1825c4b3ca2dcfe + // P.y = 05b84ae5a942248eea39e1d91030458c40153f3b654ab7872d779a + // d1e942856a20c438e8d99bc8abfbf74729ce1f7ac8 + assert_eq!(p, from_coordinates_unchecked( + Fq::from_str("1256967425542823069694513550918025689490036478501181600525944653952846100887848729514132077573887342346961531624702").unwrap(), + Fq::from_str("880372082403694543476959909256504267215588055450016885103797700856746532134585942561958795215862304181527267736264").unwrap(), + Fq::one())); + } + + #[test] + fn test_hash_to_field_fq2() { + // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-J.10.1 + let dst = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_"; + + { + // msg = + // u[0] = 03dbc2cce174e91ba93cbb08f26b917f98194a2ea08d1cce75b2b9 + // cc9f21689d80bd79b594a613d0a68eb807dfdc1cf8 + // + I * 05a2acec64114845711a54199ea339abd125ba38253b70a92c876d + // f10598bd1986b739cad67961eb94f7076511b3b39a + // u[1] = 02f99798e8a5acdeed60d7e18e9120521ba1f47ec090984662846b + // c825de191b5b7641148c0dbc237726a334473eee94 + // + I * 145a81e418d4010cc027a68f14391b30074e89e60ee7a22f87217b + // 2f6eb0c4b94c9115b436e6fa4607e95a98de30a435 + let msg = b""; + let (u0, u1) = hash_to_field_fq2(msg, dst); + assert_eq!( + u0, + Fq2{ + c0: Fq::from_str("593868448310005448561172252387029516360409945786457439875974315031640021389835649561235021338510064922970633805048").unwrap().0, + c1: Fq::from_str("867375309489067512797459860887365951877054038763818448057326190302701649888849997836339069389536967202878289851290").unwrap().0} + ); + assert_eq!( + u1, + Fq2{ + c0: Fq::from_str("457889704519948843474026022562641969443315715595459159112874498082953431971323809145630315884223143822925947137684").unwrap().0, + c1: Fq::from_str("3132697209754082586339430915081913810572071485832539443682634025529375380328136128542015469873094481703191673087029").unwrap().0} + ); + } + + { + // msg = abc + // u[0] = 15f7c0aa8f6b296ab5ff9c2c7581ade64f4ee6f1bf18f55179ff44 + // a2cf355fa53dd2a2158c5ecb17d7c52f63e7195771 + // + I * 01c8067bf4c0ba709aa8b9abc3d1cef589a4758e09ef53732d670f + // d8739a7274e111ba2fcaa71b3d33df2a3a0c8529dd + // u[1] = 187111d5e088b6b9acfdfad078c4dacf72dcd17ca17c82be35e79f + // 8c372a693f60a033b461d81b025864a0ad051a06e4 + // + I * 08b852331c96ed983e497ebc6dee9b75e373d923b729194af8e72a + // 051ea586f3538a6ebb1e80881a082fa2b24df9f566 + let msg = b"abc"; + let (u0, u1) = hash_to_field_fq2(msg, dst); + assert_eq!( + u0, + Fq2{ + c0: Fq::from_str("3381151350286428005095780827831774583653641216459357823974407145557165174365389989442078766443621078367363453769585").unwrap().0, + c1: Fq::from_str("274174695370444263853418070745339731640467919355184108253716879519695397069963034977795744692362177212201505728989").unwrap().0} + ); + assert_eq!( + u1, + Fq2{ + c0: Fq::from_str("3761918608077574755256083960277010506684793456226386707192711779006489497410866269311252402421709839991039401264868").unwrap().0, + c1: Fq::from_str("1342131492846344403298252211066711749849099599627623100864413228392326132610002371925674088601653350525231531947366").unwrap().0} + ); + } + } + + #[test] + fn test_hash_to_curve_g2() { + // Test vectors are from https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-J.10.1 + let dst = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_"; + { + // msg = + // P.x = + // 0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a + // + I * + // 05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d + // P.y = + // 0503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92 + // + I * + // 12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d6 + let msg = b""; + let p_should_be = from_coordinates_unchecked_g2( + Fq2{ + c0: Fq::from_str("193548053368451749411421515628510806626565736652086807419354395577367693778571452628423727082668900187036482254730").unwrap().0, + c1: Fq::from_str("891930009643099423308102777951250899694559203647724988361022851024990473423938537113948850338098230396747396259901").unwrap().0 + }, + Fq2{ + c0: Fq::from_str("771717272055834152378281705972671257005357145478800908373659404991537354153455452961747174765859335819766715637138").unwrap().0, + c1: Fq::from_str("2810310118582126634041133454180705304393079139103252956502404531123692847658283858246402311867775854528543237781718").unwrap().0 + }, + Fq2::one() + ); + let p = hash_to_curve_g2(msg, dst); + assert_eq!(p, p_should_be); + } + { + // msg = abc + // P.x = 02c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e6 + // + I * 139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd8 + // P.y = 1787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48 + // + I * 00aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd16 + let msg = b"abc"; + let p_should_be = from_coordinates_unchecked_g2( + Fq2{ + c0: Fq::from_str("424958340463073975547762735517193206833255107941790909009827635556634414746056077714431786321247871628515967727334").unwrap().0, + c1: Fq::from_str("3018679803970127877262826393814472528557413504329194740495363852840690589001358162447917674089074634504498585239512").unwrap().0 + }, + Fq2{ + c0: Fq::from_str("3621308185128395459888995526527127556614768604472132176060423302734876099689739385100475320409412954617897892887112").unwrap().0, + c1: Fq::from_str("102447784096837908713257069727879782642075240724579670654226801345708452018676587771714457671432122751958633012502").unwrap().0 + }, + Fq2::one() + ); + let p = hash_to_curve_g2(msg, dst); + assert_eq!(p, p_should_be); + } + { + // msg = abcdef0123456789 + // P.x = 121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd0 + // + I * 190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c + // P.y = 05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8 + // + I * 0bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be + let msg = b"abcdef0123456789"; + let p_should_be = from_coordinates_unchecked_g2( + Fq2{ + c0: Fq::from_str("2785790728239146617702443308248535381016035748520698399690132325213972292102741627498014391457605127656937478044880").unwrap().0, + c1: Fq::from_str("3855709393631831880910167818276435187147963371126198799654803099743427431977934703201153169947378798970358200024876").unwrap().0 + }, + Fq2{ + c0: Fq::from_str("821938378705205565995357931232097952117504537366318395539093959918654729488074273868834599496909844419980823111624").unwrap().0, + c1: Fq::from_str("1802420335575779950982935580421454302087567926385222707947527353462942499437987207287862072369052390195154530059198").unwrap().0 + }, + Fq2::one() + ); + let p = hash_to_curve_g2(msg, dst); + assert_eq!(p, p_should_be); + } + { + // msg = q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq + // P.x = 19a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da + // + I * 0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb91 + // P.y = 14f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192 + // + I * 09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e5662 + let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; + let p_should_be = from_coordinates_unchecked_g2( + Fq2{ + c0: Fq::from_str("3949041098513688455491231180749724794697192943196730030853285011755806989731870696216017360514887069032515603535834").unwrap().0, + c1: Fq::from_str("1416893694506131976809002935212216317132941942570763849323065381335907430566747765697423320407614734575486820936593").unwrap().0 + }, + Fq2{ + c0: Fq::from_str("3227453710863835032992962605851449401391399355135442728893790186263669279022343042444878900124369614767241382891922").unwrap().0, + c1: Fq::from_str("1498738834073759871886466122933996764471889514532827927202777922460876335493588931070034160657995151627624577390178").unwrap().0 + }, + Fq2::one() + ); + let p = hash_to_curve_g2(msg, dst); + assert_eq!(p, p_should_be); + } + { + // msg = + // a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + // P.x = + // 01a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f62534 + // + I * + // 11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d01569 + // P.y = + // 0b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e + // + I * + // 03a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab52 + let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + let p_should_be = from_coordinates_unchecked_g2( + Fq2{ + c0: Fq::from_str("254155017921606149907129844368549510385368618440139550318910532874259603395336903946742408725761795820224536519988").unwrap().0, + c1: Fq::from_str("2768431459296730426779166218544149791601585986233130583011501727704972362141149700714785450629498506208393873593705").unwrap().0 + }, + Fq2{ + c0: Fq::from_str("1755339344744337457318565116062025669984750617937721245220711425551575490663761638802010265668157125441634554205566").unwrap().0, + c1: Fq::from_str("560643043433789571968941329642646582974304556331567393300563909451776257854214387388500126524984624222885267024722").unwrap().0 + }, + Fq2::one() + ); + let p = hash_to_curve_g2(msg, dst); + assert_eq!(p, p_should_be); + } + } +} diff --git a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_g1hash.rs b/rust-src/concordium_base/src/curve_arithmetic/bls12_381_g1hash.rs deleted file mode 100644 index e955242fa..000000000 --- a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_g1hash.rs +++ /dev/null @@ -1,1549 +0,0 @@ -use ff::{Field, PrimeField}; -use group::{CurveProjective, EncodedPoint}; -use pairing::bls12_381::{Fq, FqRepr, G1Uncompressed, G1}; -use sha2::{Digest, Sha256}; -use std::{ - convert::TryInto, - io::{Cursor, Write}, -}; - -// (p-3)/4 where p is the prime characteristic of the field Fq (p=q) -#[allow(clippy::unreadable_literal)] -pub(crate) const P_MINUS_3_DIV_4: [u64; 6] = [ - 0xee7fbfffffffeaaa, - 0x07aaffffac54ffff, - 0xd9cc34a83dac3d89, - 0xd91dd2e13ce144af, - 0x92c6e9ed90d2eb35, - 0x680447a8e5ff9a6, -]; - -// The a-coefficient of the 11-isogenous curve to G1 -#[allow(clippy::unreadable_literal)] -pub(crate) const E11_A: [u64; 6] = [ - 0x5cf428082d584c1d, - 0x98936f8da0e0f97f, - 0xd8e8981aefd881ac, - 0xb0ea985383ee66a8, - 0x3d693a02c96d4982, - 0x00144698a3b8e943, -]; - -// The b-coefficient of the 11-isogenous curve to G1 -#[allow(clippy::unreadable_literal)] -pub(crate) const E11_B: [u64; 6] = [ - 0xd1cc48e98e172be0, - 0x5a23215a316ceaa5, - 0xa0b9c14fcef35ef5, - 0x2016c1f0f24f4070, - 0x018b12e8753eee3b, - 0x12e2908d11688030, -]; - -// Coefficients of the 11-isogeny rational maps, -// See https://eprint.iacr.org/2019/403.pdf section 4 -#[allow(clippy::unreadable_literal)] -pub(crate) const K1: [[u64; 6]; 12] = [ - [ - 0xaeac1662734649b7, - 0x5610c2d5f2e62d6e, - 0xf2627b56cdb4e2c8, - 0x6b303e88a2d7005f, - 0xb809101dd9981585, - 0x11a05f2b1e833340, - ], - [ - 0xe834eef1b3cb83bb, - 0x4838f2a6f318c356, - 0xf565e33c70d1e86b, - 0x7c17e75b2f6a8417, - 0x0588bab22147a81c, - 0x17294ed3e943ab2f, - ], - [ - 0xe0179f9dac9edcb0, - 0x958c3e3d2a09729f, - 0x6878e501ec68e25c, - 0xce032473295983e5, - 0x1d1048c5d10a9a1b, - 0xd54005db97678ec, - ], - [ - 0xc5b388641d9b6861, - 0x5336e25ce3107193, - 0xf1b33289f1b33083, - 0xd7f5e4656a8dbf25, - 0x4e0609d307e55412, - 0x1778e7166fcc6db7, - ], - [ - 0x51154ce9ac8895d9, - 0x985a286f301e77c4, - 0x086eeb65982fac18, - 0x99db995a1257fb3f, - 0x6642b4b3e4118e54, - 0xe99726a3199f443, - ], - [ - 0xcd13c1c66f652983, - 0xa0870d2dcae73d19, - 0x9ed3ab9097e68f90, - 0xdb3cb17dd952799b, - 0x01d1201bf7a74ab5, - 0x1630c3250d7313ff, - ], - [ - 0xddd7f225a139ed84, - 0x8da25128c1052eca, - 0x9008e218f9c86b2a, - 0xb11586264f0f8ce1, - 0x6a3726c38ae652bf, - 0xd6ed6553fe44d29, - ], - [ - 0x9ccb5618e3f0c88e, - 0x39b7c8f8c8f475af, - 0xa682c62ef0f27533, - 0x356de5ab275b4db1, - 0xe8743884d1117e53, - 0x17b81e7701abdbe2, - ], - [ - 0x6d71986a8497e317, - 0x4fa295f296b74e95, - 0xa2c596c928c5d1de, - 0xc43b756ce79f5574, - 0x7b90b33563be990d, - 0x80d3cf1f9a78fc4, - ], - [ - 0x7f241067be390c9e, - 0xa3190b2edc032779, - 0x676314baf4bb1b7f, - 0xdd2ecb803a0c5c99, - 0x2e0c37515d138f22, - 0x169b1f8e1bcfa7c4, - ], - [ - 0xca67df3f1605fb7b, - 0xf69b771f8c285dec, - 0xd50af36003b14866, - 0xfa7dccdde6787f96, - 0x72d8ec09d2565b0d, - 0x10321da079ce07e2, - ], - [ - 0xa9c8ba2e8ba2d229, - 0xc24b1b80b64d391f, - 0x23c0bf1bc24c6b68, - 0x31d79d7e22c837bc, - 0xbd1e962381edee3d, - 0x6e08c248e260e70, - ], -]; - -#[allow(clippy::unreadable_literal)] -pub(crate) const K2: [[u64; 6]; 11] = [ - [ - 0x993cf9fa40d21b1c, - 0xb558d681be343df8, - 0x9c9588617fc8ac62, - 0x01d5ef4ba35b48ba, - 0x18b2e62f4bd3fa6f, - 0x8ca8d548cff19ae, - ], - [ - 0xe5c8276ec82b3bff, - 0x13daa8846cb026e9, - 0x0126c2588c48bf57, - 0x7041e8ca0cf0800c, - 0x48b4711298e53636, - 0x12561a5deb559c43, - ], - [ - 0xfcc239ba5cb83e19, - 0xd6a3d0967c94fedc, - 0xfca64e00b11aceac, - 0x6f89416f5a718cd1, - 0x8137e629bff2991f, - 0xb2962fe57a3225e, - ], - [ - 0x130de8938dc62cd8, - 0x4976d5243eecf5c4, - 0x54cca8abc28d6fd0, - 0x5b08243f16b16551, - 0xc83aafef7c40eb54, - 0x3425581a58ae2fe, - ], - [ - 0x539d395b3532a21e, - 0x9bd29ba81f35781d, - 0x8d6b44e833b306da, - 0xffdfc759a12062bb, - 0x0a6f1d5f43e7a07d, - 0x13a8e162022914a8, - ], - [ - 0xc02df9a29f6304a5, - 0x7400d24bc4228f11, - 0x0a43bcef24b8982f, - 0x395735e9ce9cad4d, - 0x55390f7f0506c6e9, - 0xe7355f8e4e667b9, - ], - [ - 0xec2574496ee84a3a, - 0xea73b3538f0de06c, - 0x4e2e073062aede9c, - 0x570f5799af53a189, - 0x0f3e0c63e0596721, - 0x772caacf1693619, - ], - [ - 0x11f7d99bbdcc5a5e, - 0x0fa5b9489d11e2d3, - 0x1996e1cdf9822c58, - 0x6e7f63c21bca68a8, - 0x30b3f5b074cf0199, - 0x14a7ac2a9d64a8b2, - ], - [ - 0x4776ec3a79a1d641, - 0x03826692abba4370, - 0x74100da67f398835, - 0xe07f8d1d7161366b, - 0x5e920b3dafc7a3cc, - 0xa10ecf6ada54f82, - ], - [ - 0x2d6384d168ecdd0a, - 0x93174e4b4b786500, - 0x76df533978f31c15, - 0xf682b4ee96f7d037, - 0x476d6e3eb3a56680, - 0x95fc13ab9e92ad4, - ], - [0x1, 0x0, 0x0, 0x0, 0x0, 0x0], -]; - -#[allow(clippy::unreadable_literal)] -pub(crate) const K3: [[u64; 6]; 16] = [ - [ - 0xbe9845719707bb33, - 0xcd0c7aee9b3ba3c2, - 0x2b52af6c956543d3, - 0x11ad138e48a86952, - 0x259d1f094980dcfa, - 0x90d97c81ba24ee0, - ], - [ - 0xe097e75a2e41c696, - 0xd6c56711962fa8bf, - 0x0f906343eb67ad34, - 0x1223e96c254f383d, - 0xd51036d776fb4683, - 0x134996a104ee5811, - ], - [ - 0xb8dfe240c72de1f6, - 0xd26d521628b00523, - 0xc344be4b91400da7, - 0x2552e2d658a31ce2, - 0xf4a384c86a3b4994, - 0xcc786baa966e66, - ], - [ - 0xa6355c77b0e5f4cb, - 0xde405aba9ec61dec, - 0x09e4a3ec03251cf9, - 0xd42aa7b90eeb791c, - 0x7898751ad8746757, - 0x1f86376e8981c21, - ], - [ - 0x41b6daecf2e8fedb, - 0x2ee7f8dc099040a8, - 0x79833fd221351adc, - 0x195536fbe3ce50b8, - 0x5caf4fe2a21529c4, - 0x8cc03fdefe0ff13, - ], - [ - 0x99b23ab13633a5f0, - 0x203f6326c95a8072, - 0x76505c3d3ad5544e, - 0x74a7d0d4afadb7bd, - 0x2211e11db8f0a6a0, - 0x16603fca40634b6a, - ], - [ - 0xc961f8855fe9d6f2, - 0x47a87ac2460f415e, - 0x5231413c4d634f37, - 0xe75bb8ca2be184cb, - 0xb2c977d027796b3c, - 0x4ab0b9bcfac1bbc, - ], - [ - 0xa15e4ca31870fb29, - 0x42f64550fedfe935, - 0xfd038da6c26c8426, - 0x170a05bfe3bdd81f, - 0xde9926bd2ca6c674, - 0x987c8d5333ab86f, - ], - [ - 0x60370e577bdba587, - 0x69d65201c78607a3, - 0x1e8b6e6a1f20cabe, - 0x8f3abd16679dc26c, - 0xe88c9e221e4da1bb, - 0x9fc4018bd96684b, - ], - [ - 0x2bafaaebca731c30, - 0x9b3f7055dd4eba6f, - 0x06985e7ed1e4d43b, - 0xc42a0ca7915af6fe, - 0x223abde7ada14a23, - 0xe1bba7a1186bdb5, - ], - [ - 0xe813711ad011c132, - 0x31bf3a5cce3fbafc, - 0xd1183e416389e610, - 0xcd2fcbcb6caf493f, - 0x0dfd0b8f1d43fb93, - 0x19713e47937cd1be, - ], - [ - 0xce07c8a4d0074d8e, - 0x49d9cdf41b44d606, - 0x2e6bfe7f911f6432, - 0x523559b8aaf0c246, - 0xb918c143fed2edcc, - 0x18b46a908f36f6de, - ], - [ - 0x0d4c04f00b971ef8, - 0x06c851c1919211f2, - 0xc02710e807b4633f, - 0x7aa7b12a3426b08e, - 0xd155096004f53f44, - 0xb182cac101b9399, - ], - [ - 0x42d9d3f5db980133, - 0xc6cf90ad1c232a64, - 0x13e6632d3c40659c, - 0x757b3b080d4c1580, - 0x72fc00ae7be315dc, - 0x245a394ad1eca9b, - ], - [ - 0x866b1e715475224b, - 0x6ba1049b6579afb7, - 0xd9ab0f5d396a7ce4, - 0x5e673d81d7e86568, - 0x02a159f748c4a3fc, - 0x5c129645e44cf11, - ], - [ - 0x04b456be69c8b604, - 0xb665027efec01c77, - 0x57add4fa95af01b2, - 0xcb181d8f84965a39, - 0x4ea50b3b42df2eb5, - 0x15e6be4e990f03ce, - ], -]; - -#[allow(clippy::unreadable_literal)] -pub(crate) const K4: [[u64; 6]; 16] = [ - [ - 0x01479253b03663c1, - 0x07f3688ef60c206d, - 0xeec3232b5be72e7a, - 0x601a6de578980be6, - 0x52181140fad0eae9, - 0x16112c4c3a9c98b2, - ], - [ - 0x32f6102c2e49a03d, - 0x78a4260763529e35, - 0xa4a10356f453e01f, - 0x85c84ff731c4d59c, - 0x1a0cbd6c43c348b8, - 0x1962d75c2381201e, - ], - [ - 0x1e2538b53dbf67f2, - 0xa6757cd636f96f89, - 0x0c35a5dd279cd2ec, - 0x78c4855551ae7f31, - 0x6faaae7d6e8eb157, - 0x58df3306640da27, - ], - [ - 0xa8d26d98445f5416, - 0x727364f2c28297ad, - 0x123da489e726af41, - 0xd115c5dbddbcd30e, - 0xf20d23bf89edb4d1, - 0x16b7d288798e5395, - ], - [ - 0xda39142311a5001d, - 0xa20b15dc0fd2eded, - 0x542eda0fc9dec916, - 0xc6d19c9f0f69bbb0, - 0xb00cc912f8228ddc, - 0xbe0e079545f43e4, - ], - [ - 0x02c6477faaf9b7ac, - 0x49f38db9dfa9cce2, - 0xc5ecd87b6f0f5a64, - 0xb70152c65550d881, - 0x9fb266eaac783182, - 0x8d9e5297186db2d, - ], - [ - 0x3d1a1399126a775c, - 0xd5fa9c01a58b1fb9, - 0x5dd365bc400a0051, - 0x5eecfdfa8d0cf8ef, - 0xc3ba8734ace9824b, - 0x166007c08a99db2f, - ], - [ - 0x60ee415a15812ed9, - 0xb920f5b00801dee4, - 0xfeb34fd206357132, - 0xe5a4375efa1f4fd7, - 0x03bcddfabba6ff6e, - 0x16a3ef08be3ea7ea, - ], - [ - 0x6b233d9d55535d4a, - 0x52cfe2f7bb924883, - 0xabc5750c4bf39b48, - 0xf9fb0ce4c6af5920, - 0x1a1be54fd1d74cc4, - 0x1866c8ed336c6123, - ], - [ - 0x346ef48bb8913f55, - 0xc7385ea3d529b35e, - 0x5308592e7ea7d4fb, - 0x3216f763e13d87bb, - 0xea820597d94a8490, - 0x167a55cda70a6e1c, - ], - [ - 0x00f8b49cba8f6aa8, - 0x71a5c29f4f830604, - 0x0e591b36e636a5c8, - 0x9c6dd039bb61a629, - 0x48f010a01ad2911d, - 0x4d2f259eea405bd, - ], - [ - 0x9684b529e2561092, - 0x16f968986f7ebbea, - 0x8c0f9a88cea79135, - 0x7f94ff8aefce42d2, - 0xf5852c1e48c50c47, - 0xaccbb67481d033f, - ], - [ - 0x1e99b138573345cc, - 0x93000763e3b90ac1, - 0x7d5ceef9a00d9b86, - 0x543346d98adf0226, - 0xc3613144b45f1496, - 0xad6b9514c767fe3, - ], - [ - 0xd1fadc1326ed06f7, - 0x420517bd8714cc80, - 0xcb748df27942480e, - 0xbf565b94e72927c1, - 0x628bdd0d53cd76f2, - 0x2660400eb2e4f3b, - ], - [ - 0x4415473a1d634b8f, - 0x5ca2f570f1349780, - 0x324efcd6356caa20, - 0x71c40f65e273b853, - 0x6b24255e0d7819c1, - 0xe0fa1d816ddc03e, - ], - [0x1, 0x0, 0x0, 0x0, 0x0, 0x0], -]; - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-3 -/// It follows the steps -/// 1. u = hash_to_field(msg, 2) -/// 2. Q0 = map_to_curve(u[0]) -/// 3. Q1 = map_to_curve(u[1]) -/// 4. R = Q0 + Q1 -/// 5. P = clear_cofactor(R) = h_eff * R # Clearing cofactor -/// 6. return P, -/// where the choices of hash_to_field, map_to_curve and h_eff are as described in https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-8.8.1. -pub fn hash_to_curve(msg: &[u8], dst: &[u8]) -> G1 { - let (u0, u1) = hash_to_field(msg, dst); - - let q0 = map_to_curve(u0); // This is on E, but not necessarily in G1 - let q1 = map_to_curve(u1); // This is on E, but not necessarily in G1 - - let mut r = q0; - r.add_assign(&q1); // This is on E, but not necessarily in G1 - r.mul_assign(15132376222941642753); // Clearing cofactor with h_eff = 15132376222941642753 - r // This now guarantied to be in G1 -} - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.6.3 -/// It uses the function sswu_3mod4 to get xn, xd, y such that (xn/xd : y : 1) -/// is a point on E' (written in Jacobian coordinates). Since inversions are -/// expensive, we use the fact that (xn/xd : y : 1) on E' <=> (xn xd : xd^3y : -/// xd) on E' when using Jacobian coordinates. It returns iso_11((xn xd : xd^3y -/// : xd)) which is then guarenteed to lie on E (but not necessarily in G1). -fn map_to_curve(u: Fq) -> G1 { - let (mut x, xd, mut y, _) = sswu_3mod4(u); - x.mul_assign(&xd); - y.mul_assign(&xd); - y.mul_assign(&xd); - y.mul_assign(&xd); - let (xiso, yiso, z) = iso_11(x, y, xd); - from_coordinates_unchecked(xiso, yiso, z) -} - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-3 -/// with the choice of expand_message being expand_message_xmd, as specified in https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-8.8.1. -fn hash_to_field(msg: &[u8], dst: &[u8]) -> (Fq, Fq) { - let (u_0, u_1, u_2, u_3) = expand_message_xmd(msg, dst); - - (fq_from_bytes(&u_0, &u_1), fq_from_bytes(&u_2, &u_3)) -} - -// Interpret input as integers (big endian) -// Return (left*2^256 + right) as Fq -fn fq_from_bytes(left_bytes: &[u8; 32], right_bytes: &[u8; 32]) -> Fq { - fn le_u64s_from_be_bytes(bytes: &[u8; 32]) -> Fq { - let mut digits = [0u64; 6]; - - for (place, chunk) in digits.iter_mut().zip(bytes.chunks(8).rev()) { - *place = u64::from_be_bytes(chunk.try_into().expect("Chunk Sie is always 8")) - } - - Fq::from_repr(FqRepr(digits)).expect("Only the leading 4 u64s are initialized") - } - - let two_to_256_fqrepr = [0u64, 0, 0, 0, 1, 0]; // 2^256 - let two_to_256_fq = Fq::from_repr(FqRepr(two_to_256_fqrepr)).expect("2^256 fits in modulus"); - - let mut left_fq = le_u64s_from_be_bytes(left_bytes); - let right_fq = le_u64s_from_be_bytes(right_bytes); - left_fq.mul_assign(&two_to_256_fq); // u_0[..32] * 2^256 - left_fq.add_assign(&right_fq); // u_0[32..] + u_0[32..] * 2^256 = u_0 - - left_fq -} - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-5.4.1 -/// len_in_bytes is fixed to 128 -/// Domain separation string (dst) should be at most 255 bytes -fn expand_message_xmd(msg: &[u8], dst: &[u8]) -> ([u8; 32], [u8; 32], [u8; 32], [u8; 32]) { - // DST_prime = DST || I2OSP(len(DST), 1) - let mut dst_prime = dst.to_vec(); - dst_prime.push(dst.len().try_into().unwrap()); // panics if dst is more than 255 bytes - // msg_prime = Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime - - // b_0 = H(msg_prime) - let mut h = Sha256::new(); - // todo a possible optimization here would be to save the state of H(Z_pad) - h.update(vec![0; 64]); // z_pad = I2OSP(0, 64), 64 is the input block size of Sha265 - h.update(msg); - h.update(vec![0, 128]); // l_i_b_str = I2OSP(128, 2) - h.update([0u8]); - h.update(&dst_prime); - let mut b_0: [u8; 32] = [0u8; 32]; - b_0.copy_from_slice(h.finalize().as_slice()); - - // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) - let mut h = Sha256::new(); - h.update(b_0); - h.update([1u8]); - h.update(&dst_prime); - let mut b_1: [u8; 32] = [0u8; 32]; - b_1.copy_from_slice(h.finalize().as_slice()); - - // b_2 = H(strxor(b_0, b_1) || I2OSP(2, 1) || DST_prime) - let mut h = Sha256::new(); - let xor: Vec = b_0.iter().zip(b_1.iter()).map(|(x, y)| x ^ y).collect(); - h.update(xor); - h.update([2u8]); - h.update(&dst_prime); - let mut b_2: [u8; 32] = [0u8; 32]; - b_2.copy_from_slice(h.finalize().as_slice()); - - // b_3 = H(strxor(b_1, b_2) || I2OSP(3, 1) || DST_prime) - let mut h = Sha256::new(); - let xor: Vec = b_0.iter().zip(b_2.iter()).map(|(x, y)| x ^ y).collect(); - h.update(xor); - h.update([3u8]); - h.update(&dst_prime); - let mut b_3: [u8; 32] = [0u8; 32]; - b_3.copy_from_slice(h.finalize().as_slice()); - - // b_4 = H(strxor(b_2, b_3) || I2OSP(4, 1) || DST_prime) - let mut h = Sha256::new(); - let xor: Vec = b_0.iter().zip(b_3.iter()).map(|(x, y)| x ^ y).collect(); - h.update(xor); - h.update([4u8]); - h.update(dst_prime); - let mut b_4: [u8; 32] = [0u8; 32]; - b_4.copy_from_slice(h.finalize().as_slice()); - - (b_1, b_2, b_3, b_4) -} - -// Returns a point on E1 with coordinates x,y,z. -// CAREFUL! This point is NOT guaranteed to be in the correct order subgroup -// To get the point into the correct order subgroup, multiply by 1 + -// 15132376222941642752 -#[inline] -fn from_coordinates_unchecked(x: Fq, y: Fq, z: Fq) -> G1 { - if z.is_zero() { - G1::zero() - } else { - let z_inv = z.inverse().unwrap(); - let mut z_inv2 = z_inv; - z_inv2.square(); - let mut p_x = x; - p_x.mul_assign(&z_inv2); - let mut p_y = y; - p_y.mul_assign(&z_inv); - p_y.mul_assign(&z_inv2); - - let mut uncompress_point = G1Uncompressed::empty(); - let mut cursor = Cursor::new(uncompress_point.as_mut()); - - for digit in p_x.into_repr().as_ref().iter().rev() { - cursor - .write_all(&digit.to_be_bytes()) - .expect("This write will always succeed."); - } - for digit in p_y.into_repr().as_ref().iter().rev() { - cursor - .write_all(&digit.to_be_bytes()) - .expect("This write will always succeed."); - } - - // The below is safe, since xiso, yiso, z are in Fq. - // The into_affine_unchecked() used below can fail if - // at least one of the bits representing 2^5, 2^6 or 2^7 in the first entry of - // the `uncompress_point` are set, but this will not happen. - // The field size q is - // 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787, - // and and since 27 * 2^(47*8) > q, the first entry of - // `uncompress_point` will always be < 27 < 2^5, since this entry - // represents the number of 2^(47*8)'s. - let res = uncompress_point.into_affine_unchecked(); - G1::from(res.expect("Should not happen, since input coordinates are in Fq.")) - } -} - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-G.2.1 -/// Input: u, an element of Fq. -/// Output: (xn, xd, yn, yd) such that (xn / xd, yn / yd) is a -/// point on E'. -#[allow(clippy::many_single_char_names)] -fn sswu_3mod4(u: Fq) -> (Fq, Fq, Fq, Fq) { - let a = Fq::from_repr(FqRepr(E11_A)).unwrap(); // this unwrap can't fail, E11_A is an element of the field - let b = Fq::from_repr(FqRepr(E11_B)).unwrap(); // this unwrap can't fail, E11_B is an element of the field - // Constants: - // 1. c1 = (q - 3) / 4 # Integer arithmetic - // 2. c2 = sqrt(-Z^3) - // Z = 11 - let z = Fq::from_repr(FqRepr::from(11)).unwrap(); - // c2 = sqrt(-z^3) - let c2 = Fq::from_repr(FqRepr([ - 8011268957077696501, - 9962099387040634336, - 8623975380491602827, - 7731696418485440718, - 18010667617739806336, - 276559961644294862, - ])) - .unwrap(); - - // Steps: - // 1. tv1 = u^2 - let mut tv1 = u; - tv1.square(); - - // 2. tv3 = Z * tv1 - let mut tv3 = z; - tv3.mul_assign(&tv1); - - // 3. tv2 = tv3^2 - let mut tv2 = tv3; - tv2.square(); - - // 4. xd = tv2 + tv3 - let mut xd = tv2; - xd.add_assign(&tv3); - - // 5. x1n = xd + 1 - // 6. x1n = x1n * B - let mut x1n = xd; - x1n.add_assign(&Fq::one()); - x1n.mul_assign(&b); - - // 7. xd = -A * xd - let mut neg_a = a; - neg_a.negate(); - xd.mul_assign(&neg_a); - - // 8. e1 = xd == 0 - let e1 = xd.is_zero(); - - // 9. xd = CMOV(xd, Z * A, e1) # If xd == 0, set xd = Z * A - // We don't care if this is constant time or not. - if e1 { - xd = z; - xd.mul_assign(&a); - } - - // 10. tv2 = xd^2 - tv2 = xd; - tv2.square(); - - // 11. gxd = tv2 * xd # gxd == xd^3 - let mut gxd = tv2; - gxd.mul_assign(&xd); - - // 12. tv2 = A * tv2 - tv2.mul_assign(&a); - - // 13. gx1 = x1n^2 - let mut gx1 = x1n; - gx1.square(); - - // 14. gx1 = gx1 + tv2 # x1n^2 + A * xd^2 - gx1.add_assign(&tv2); - - // 15. gx1 = gx1 * x1n # x1n^3 + A * x1n * xd^2 - gx1.mul_assign(&x1n); - - // 16. tv2 = B * gxd - tv2 = b; - tv2.mul_assign(&gxd); - - // 17. gx1 = gx1 + tv2 # x1n^3 + A * x1n * xd^2 + B * xd^3 - gx1.add_assign(&tv2); - - // 18. tv4 = gxd^2 - let mut tv4 = gxd; - tv4.square(); - - // 19. tv2 = gx1 * gxd - tv2 = gx1; - tv2.mul_assign(&gxd); - - // 20. tv4 = tv4 * tv2 # gx1 * gxd^3 - tv4.mul_assign(&tv2); - - // 21. y1 = tv4^c1 # (gx1 * gxd^3)^((q - 3) / 4) - let mut y1 = tv4; - y1 = y1.pow(P_MINUS_3_DIV_4); - - // 22. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((q - 3) / 4) - y1.mul_assign(&tv2); - - // 23. x2n = tv3 * x1n # x2 = x2n / xd = Z * u^2 * x1n / xd - let mut x2n = tv3; - x2n.mul_assign(&x1n); - - // 24. y2 = y1 * c2 # y2 = y1 * sqrt(-Z^3) - let mut y2 = y1; - y2.mul_assign(&c2); - - // 25. y2 = y2 * tv1 - y2.mul_assign(&tv1); - - // 26. y2 = y2 * u - y2.mul_assign(&u); - - // 27. tv2 = y1^2 - tv2 = y1; - tv2.square(); - - // 28. tv2 = tv2 * gxd - tv2.mul_assign(&gxd); - - // 29. e2 = tv2 == gx1 - tv2.sub_assign(&gx1); - let e2 = tv2.is_zero(); - - let mut xn = x2n; - let mut y = y2; - // 30. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2 - // 31. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2 - if e2 { - xn = x1n; - y = y1; - } - - // 32. e3 = sgn0(u) == sgn0(y) # Fix sign of y - let e3 = sgn0(u) == sgn0(y); - - // 33. y = CMOV(-y, y, e3) - if !e3 { - y.negate(); - } - - // 34. return (xn, xd, y, 1) - // i.e. (xn / xd, y) is a point on the target curve - - (xn, xd, y, Fq::one()) -} - -/// Computes the 11-isogeny E1'(Fq): y^2 = x^3 + E11_A x + E11_B -/// used for hashing -fn iso_11(x: Fq, y: Fq, z: Fq) -> (Fq, Fq, Fq) { - // Compute Z^2i for i = 1,...,15 - let mut z_pow_2i: [Fq; 15] = [z; 15]; - z_pow_2i[0].square(); // Z^2 - z_pow_2i[1] = z_pow_2i[0]; - z_pow_2i[1].square(); // Z^4 - let mut z_ = z_pow_2i[1]; - z_.mul_assign(&z_pow_2i[0]); - z_pow_2i[2] = z_; // Z^6 - z_pow_2i[3] = z_pow_2i[1]; - z_pow_2i[3].square(); // Z^8 - for i in 0..3 { - // Z^10, Z^12, Z^14, - z_ = z_pow_2i[3 + i]; - z_.mul_assign(&z_pow_2i[0]); - z_pow_2i[4 + i] = z_; - } - z_pow_2i[7] = z_pow_2i[3]; - z_pow_2i[7].square(); // Z^16 - for i in 0..7 { - // Z^18, Z^20, Z^22, Z^24, Z^26, Z^28, Z^30, - z_ = z_pow_2i[7 + i]; - z_.mul_assign(&z_pow_2i[0]); - z_pow_2i[8 + i] = z_; - } - - let x_num = horner(&K1, &z_pow_2i, &x); - - let x_den_ = horner(&K2, &z_pow_2i, &x); - let mut x_den = z_pow_2i[0]; - x_den.mul_assign(&x_den_); - - let y_num_ = horner(&K3, &z_pow_2i, &x); - let mut y_num = y; - y_num.mul_assign(&y_num_); - - let y_den_ = horner(&K4, &z_pow_2i, &x); - let mut y_den = z_pow_2i[0]; - y_den.mul_assign(&z); - y_den.mul_assign(&y_den_); - - let mut z_jac = x_den; - z_jac.mul_assign(&y_den); - let mut x_jac = x_num; - x_jac.mul_assign(&y_den); - x_jac.mul_assign(&z_jac); - let mut z_jac_pow2 = z_jac; - z_jac_pow2.square(); - let mut y_jac = y_num; - y_jac.mul_assign(&x_den); - y_jac.mul_assign(&z_jac_pow2); - - (x_jac, y_jac, z_jac) -} - -/// Function for evaluating polynomials using Horner's rule -/// Donald E. Knuth. Seminumerical Algorithms, volume 2 of The Art of Computer -/// Programming, chapter 4.6.4. Addison-Wesley, 3rd edition, 1997 -/// -/// Evaluates the polynomial with the given coefficients where the i'th -/// coefficient has been multiplied by z^(degree - i) where degree is the degree -/// of the polynomial. -/// z_powers is an array of the even powers of z, ordered [z^2, z^4, ...] The -/// polynomial is evaluated in 'variable'. Note: It's a prerequisite that -/// Fq::from_repr(FqRepr(coefficient[i])) doesn't produce an error!!! -fn horner(coefficients: &[[u64; 6]], z_powers: &[Fq], variable: &Fq) -> Fq { - let clen = coefficients.len(); - // unwrapping the Ki constants never fails - let mut res = Fq::from_repr(FqRepr(coefficients[clen - 1])).unwrap(); - // skip the last coefficient since we already used it - for (coeff, pow) in coefficients.iter().rev().skip(1).zip(z_powers.iter()) { - res.mul_assign(variable); - let mut coeff = Fq::from_repr(FqRepr(*coeff)).unwrap(); // unwrapping the Ki constants never fails - coeff.mul_assign(pow); - res.add_assign(&coeff); - } - res -} - -/// The function sgn0 given at https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-4.1 -fn sgn0(a: Fq) -> u64 { - let repr = a.into_repr(); - let ones = repr.0[0]; - ones % 2 -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::common::to_bytes; - use byteorder::{BigEndian, ReadBytesExt}; - use ff::SqrtField; - use rand::{rngs::StdRng, thread_rng, SeedableRng}; - - // testing from_coordinates_unchecked for point at infinity - #[test] - fn test_from_coordinates_point_at_infinity() { - let mut rng: StdRng = SeedableRng::from_rng(thread_rng()).unwrap(); - - let expected = G1::zero(); - let z = Fq::zero(); - for _ in 0..1000 { - let x = Fq::random(&mut rng); - let y = Fq::random(&mut rng); - let paf = from_coordinates_unchecked(x, y, z); - - assert!(paf == expected); - } - } - - // testing from_coordinates_unchecked for random points - #[test] - fn test_from_coordinates() { - let mut rng: StdRng = SeedableRng::from_rng(thread_rng()).unwrap(); - - let mut i = 0; - while i <= 10000 { - let x = Fq::random(&mut rng); - let mut y = x; - y.square(); - y.mul_assign(&x); - y.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); - match y.sqrt() { - Some(sqrt) => { - let p = from_coordinates_unchecked(x, sqrt, Fq::one()); - println!("{:?}", p); - - let encodedpoint = G1Uncompressed::from_affine(p.into_affine()); - let mut xref = &encodedpoint.as_ref()[0..48]; - let mut yref = &encodedpoint.as_ref()[48..96]; - - let mut xrepr = FqRepr([0u64; 6]); - for digit in xrepr.as_mut().iter_mut().rev() { - *digit = xref.read_u64::().unwrap(); - } - - assert!(Fq::from_repr(xrepr).unwrap() == x); - - let mut yrepr = FqRepr([0u64; 6]); - for digit in yrepr.as_mut().iter_mut().rev() { - *digit = yref.read_u64::().unwrap(); - } - - println!("y = {:?}", sqrt); - let actual_y = Fq::from_repr(yrepr).unwrap(); - println!("actual_y = {:?}", actual_y); - assert!(actual_y == sqrt); - - i += 1; - } - None => (), - }; - } - } - - macro_rules! test_isogeny_constants { - ($test_name:ident, $l:expr) => { - #[test] - fn $test_name() { - for k in $l { - let fq_ = Fq::from_repr(FqRepr(*k)).unwrap(); - let repr = fq_.into_repr(); - assert!(FqRepr(*k) == repr); - } - } - }; - } - - test_isogeny_constants!(test_k1, &K1); - test_isogeny_constants!(test_k2, &K2); - test_isogeny_constants!(test_k3, &K3); - test_isogeny_constants!(test_k4, &K4); - - macro_rules! test_const { - ($test_name:ident, $k:expr) => { - #[test] - fn $test_name() { - let fq_ = Fq::from_repr(FqRepr($k)).unwrap(); - let repr = fq_.into_repr(); - assert!(FqRepr($k) == repr); - } - }; - } - - test_const!(test_e11_a, E11_A); - test_const!(test_e11_b, E11_B); - test_const!(test_p_minus_3_div_4, P_MINUS_3_DIV_4); - - #[test] - fn test_iso11() { - fn test_isogeny_map(x: Fq, y: Fq, z: Fq, x_expected: Fq, y_expected: Fq, z_expected: Fq) { - let (x_iso, y_iso, z_iso) = iso_11(x, y, z); - - let z_inverse = z_iso.inverse().unwrap(); - let mut z_inverse2 = z_inverse; - z_inverse2.square(); - let mut z_inverse3 = z_inverse2; - z_inverse3.mul_assign(&z_inverse); - let mut x_iso = x_iso; - x_iso.mul_assign(&z_inverse2); - let mut y_iso = y_iso; - y_iso.mul_assign(&z_inverse3); - let mut z_iso = z_iso; - z_iso.mul_assign(&z_inverse); - - assert!(x_expected == x_iso); - assert!(y_expected == y_iso); - assert!(z_expected == z_iso); - } - - // test case 1, affine point on 11-isogeny: - // x: 231676323333219032364207663160931012408135689080701790049416995747433764605315759399331076266193515570430995049583, - // y: 1679701275502850236404761224635518110616107305447740765847030766801057551645601784778242705363960817147253464979660 - // - // resulting affine point on y^2 = x^3 + 4, computed using Sage: - // x: 2462470316687406725265935944033330307865993658929330879249576046234792668690184598793893670391772666445389495997970 - // y: 1305585544177362738895827194786305935351300563185311476107805270117356948076235166602872188538678439100090683175388 - let x = Fq::from_repr(FqRepr([ - 0x68608ed954cbac6f, - 0x65676cfc0f8bfb80, - 0xd70a6c11c45d1c07, - 0x7e8458a01605e048, - 0xff5d19ee27f38db3, - 0x18156d91aae27cc, - ])) - .unwrap(); - let y = Fq::from_repr(FqRepr([ - 0xddb6c5f190d758cc, - 0x5b3e6c9220fc6a55, - 0xe052aaf632d5ffcf, - 0xc4c8305e904e5446, - 0x70beb5d30c08ee74, - 0xae9ca0eb3be343e, - ])) - .unwrap(); - let z = Fq::from_repr(FqRepr([1, 0, 0, 0, 0, 0])).unwrap(); - let x_expected = Fq::from_repr(FqRepr([ - 0x579fc665b50b1612, - 0x84f14441fecfb0d8, - 0x7dbc911b151848c7, - 0xd96c755dd2b0a190, - 0xe9fc535fe433bf3b, - 0xfffbdf8b8989a76, - ])) - .unwrap(); - let y_expected = Fq::from_repr(FqRepr([ - 0x93ab61d6e91b31dc, - 0x1042678018e3cdc7, - 0x9027928a6135e9ad, - 0x00f896c024c7bfcc, - 0xa40980cf7b0ad597, - 0x87b8914dbe39524, - ])) - .unwrap(); - let z_expected = Fq::from_repr(FqRepr([1, 0, 0, 0, 0, 0])).unwrap(); - test_isogeny_map(x, y, z, x_expected, y_expected, z_expected); - - // test case 2, affine point on 11-isogeny: - // x: 200672990962149954463803146802967864720527670550092954518341273224587459684808873511630728943600649771874365573754 - // y: 3771658320633238787764443471835928880231542729858183816905716275784304196017898359904922975462921081984123896844037 - // the x,y,z coordinates below are the jacobian coordinates (x*1000000^2, - // y*1000000^3, 1000000) - // - // resulting affine point on y^2 = x^3 + 4, computed using Sage: - // x: 751464328052491409370915162588147071834631858446608699879213045826820895244140093535995699583970173378180279055064 - // y: 3766342793094137890660475956436782650146903774069499310802413350809867070503035142752911481430587061848145471128246 - let x = Fq::from_repr(FqRepr([ - 0x71ae3b7c4614ac63, - 0x0645eeb5fe9a5714, - 0xc3ce0a80be8d8e34, - 0xd63ecf7124c3f319, - 0x5d8492ffc6f05671, - 0xadc0dda804ea96a, - ])) - .unwrap(); - let y = Fq::from_repr(FqRepr([ - 0xf4112fd0ccb6f2a7, - 0x7425fc157162679e, - 0x6de4be0915cc3a49, - 0x08239de97826c864, - 0x288f77250bf33de4, - 0x247b456e0a426b8, - ])) - .unwrap(); - let z = Fq::from_repr(FqRepr([0xf4240, 0, 0, 0, 0, 0])).unwrap(); - let x_expected = Fq::from_repr(FqRepr([ - 0x6a2e445da19e32d8, - 0x686f68e3be0c200e, - 0x66626a48f825305c, - 0x900b2832f3b69833, - 0x48949ce6f9ba8435, - 0x4e1e27e358d07c1, - ])) - .unwrap(); - let y_expected = Fq::from_repr(FqRepr([ - 0xc9483a6d60dec2b6, - 0x8b8586d8c8ca556f, - 0x09279c0316e87332, - 0x348bd993c7cadb0c, - 0xf5a74b1bb7ab0896, - 0x18786da2bb432953, - ])) - .unwrap(); - let z_expected = Fq::from_repr(FqRepr([1, 0, 0, 0, 0, 0])).unwrap(); - test_isogeny_map(x, y, z, x_expected, y_expected, z_expected); - } - - // This tests the expand_message_xmd function - // Test vectors for expand_message_xmd from - // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-K.1 - // DST = QUUX-V01-CS02-with-expander - // hash = SHA256 - // len_in_bytes = 0x80 - #[test] - fn test_expand_message_xmd() { - let domain_string = "QUUX-V01-CS02-with-expander"; - let dst = domain_string.as_bytes(); - { - // msg = - // uniform_bytes = - // 8bcffd1a3cae24cf9cd7ab85628fd111bb17e3739d3b53f89580d217aa79526f - // - // 1708354a76a402d3569d6a9d19ef3de4d0b991e4f54b9f20dcde9b95a66824cb - // - // df6c1a963a1913d43fd7ac443a02fc5d9d8d77e2071b86ab114a9f34150954a7 - // - // 531da568a1ea8c760861c0cde2005afc2c114042ee7b5848f5303f0611cf297f - - let msg = "".as_bytes(); - let (a, b, c, d) = expand_message_xmd(msg, dst); - - assert_eq!(a.to_vec(), vec![ - 0x8b, 0xcf, 0xfd, 0x1a, 0x3c, 0xae, 0x24, 0xcf, 0x9c, 0xd7, 0xab, 0x85, 0x62, 0x8f, - 0xd1, 0x11, 0xbb, 0x17, 0xe3, 0x73, 0x9d, 0x3b, 0x53, 0xf8, 0x95, 0x80, 0xd2, 0x17, - 0xaa, 0x79, 0x52, 0x6f - ]); - assert_eq!(b.to_vec(), vec![ - 0x17, 0x08, 0x35, 0x4a, 0x76, 0xa4, 0x02, 0xd3, 0x56, 0x9d, 0x6a, 0x9d, 0x19, 0xef, - 0x3d, 0xe4, 0xd0, 0xb9, 0x91, 0xe4, 0xf5, 0x4b, 0x9f, 0x20, 0xdc, 0xde, 0x9b, 0x95, - 0xa6, 0x68, 0x24, 0xcb - ]); - assert_eq!(c.to_vec(), vec![ - 0xdf, 0x6c, 0x1a, 0x96, 0x3a, 0x19, 0x13, 0xd4, 0x3f, 0xd7, 0xac, 0x44, 0x3a, 0x02, - 0xfc, 0x5d, 0x9d, 0x8d, 0x77, 0xe2, 0x07, 0x1b, 0x86, 0xab, 0x11, 0x4a, 0x9f, 0x34, - 0x15, 0x09, 0x54, 0xa7 - ]); - assert_eq!(d.to_vec(), vec![ - 0x53, 0x1d, 0xa5, 0x68, 0xa1, 0xea, 0x8c, 0x76, 0x08, 0x61, 0xc0, 0xcd, 0xe2, 0x00, - 0x5a, 0xfc, 0x2c, 0x11, 0x40, 0x42, 0xee, 0x7b, 0x58, 0x48, 0xf5, 0x30, 0x3f, 0x06, - 0x11, 0xcf, 0x29, 0x7f - ]); - } - - { - // msg = abc - // uniform_bytes = - // fe994ec51bdaa821598047b3121c149b364b178606d5e72bfbb713933acc29c1 - // - // 86f316baecf7ea22212f2496ef3f785a27e84a40d8b299cec56032763eceeff4 - // - // c61bd1fe65ed81decafff4a31d0198619c0aa0c6c51fca15520789925e813dcf - // - // d318b542f8799441271f4db9ee3b8092a7a2e8d5b75b73e28fb1ab6b4573c192 - - let msg = "abc".as_bytes(); - let (a, b, c, d) = expand_message_xmd(msg, dst); - - assert_eq!(a.to_vec(), vec![ - 0xfe, 0x99, 0x4e, 0xc5, 0x1b, 0xda, 0xa8, 0x21, 0x59, 0x80, 0x47, 0xb3, 0x12, 0x1c, - 0x14, 0x9b, 0x36, 0x4b, 0x17, 0x86, 0x06, 0xd5, 0xe7, 0x2b, 0xfb, 0xb7, 0x13, 0x93, - 0x3a, 0xcc, 0x29, 0xc1 - ]); - assert_eq!(b.to_vec(), vec![ - 0x86, 0xf3, 0x16, 0xba, 0xec, 0xf7, 0xea, 0x22, 0x21, 0x2f, 0x24, 0x96, 0xef, 0x3f, - 0x78, 0x5a, 0x27, 0xe8, 0x4a, 0x40, 0xd8, 0xb2, 0x99, 0xce, 0xc5, 0x60, 0x32, 0x76, - 0x3e, 0xce, 0xef, 0xf4 - ]); - assert_eq!(c.to_vec(), vec![ - 0xc6, 0x1b, 0xd1, 0xfe, 0x65, 0xed, 0x81, 0xde, 0xca, 0xff, 0xf4, 0xa3, 0x1d, 0x01, - 0x98, 0x61, 0x9c, 0x0a, 0xa0, 0xc6, 0xc5, 0x1f, 0xca, 0x15, 0x52, 0x07, 0x89, 0x92, - 0x5e, 0x81, 0x3d, 0xcf - ]); - assert_eq!(d.to_vec(), vec![ - 0xd3, 0x18, 0xb5, 0x42, 0xf8, 0x79, 0x94, 0x41, 0x27, 0x1f, 0x4d, 0xb9, 0xee, 0x3b, - 0x80, 0x92, 0xa7, 0xa2, 0xe8, 0xd5, 0xb7, 0x5b, 0x73, 0xe2, 0x8f, 0xb1, 0xab, 0x6b, - 0x45, 0x73, 0xc1, 0x92 - ]); - } - } - - // For testing that a point is on the curve E: y^2 = x^3 + 4 - fn is_on_curve(x: Fq, y: Fq) -> bool { - let mut y2 = y; - y2.square(); - let mut x3b = x; - x3b.square(); - x3b.mul_assign(&x); - x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); - y2 == x3b - } - - // For testing that a point is on the curve E': y^2 = x^3 + E11_A x + E11_B - fn is_on_curve_iso(x: Fq, y: Fq) -> bool { - let mut y2 = y; - y2.square(); - - let mut x3axb = x; - x3axb.square(); - x3axb.mul_assign(&x); - - let mut ax = Fq::from_repr(FqRepr(E11_A)).unwrap(); // this unwrap can't fail, E11_A is an element of the field - ax.mul_assign(&x); - x3axb.add_assign(&ax); - - let b = Fq::from_repr(FqRepr(E11_B)).unwrap(); // this unwrap can't fail, E11_B is an element of the field - x3axb.add_assign(&b); - y2 == x3axb - } - - // Only for testing the sswu_3mod4 function. - fn horners_simple(coefficients: &[[u64; 6]], variable: &Fq) -> Fq { - let clen = coefficients.len(); - // unwrapping the Ki constants never fails - let mut res = Fq::from_repr(FqRepr(coefficients[clen - 1])).unwrap(); - // skip the last coefficient since we already used it - for coeff in coefficients.iter().rev().skip(1) { - res.mul_assign(variable); - let coeff = Fq::from_repr(FqRepr(*coeff)).unwrap(); // unwrapping the Ki constants never fails - res.add_assign(&coeff); - } - res - } - - // Only for testing the sswu_3mod4 function. - fn iso_map(x: &Fq, y: &Fq) -> (Fq, Fq) { - let mut x_num = horners_simple(&K1, x); - let x_den = horners_simple(&K2, x); - x_num.mul_assign(&x_den.inverse().unwrap()); - let mut y_num = horners_simple(&K3, x); - let y_den = horners_simple(&K4, x); - y_num.mul_assign(&y_den.inverse().unwrap()); - y_num.mul_assign(y); - - (x_num, y_num) - } - - // Only for testing the sswu_3mod4 function. - fn test_sswu_3mod4_helper(msg: &[u8]) -> (Fq, Fq, Fq, Fq) { - let dst = "QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_".as_bytes(); - let (u0, u1) = hash_to_field(msg, dst); - let (q0xn, q0xd, q0y, _) = sswu_3mod4(u0); - let (q1xn, q1xd, q1y, _) = sswu_3mod4(u1); - let mut q0x = q0xn; - q0x.mul_assign(&q0xd.inverse().unwrap()); - let mut q1x = q1xn; - q1x.mul_assign(&q1xd.inverse().unwrap()); - let (q0xiso, q0yiso) = iso_map(&q0x, &q0y); - let (q1xiso, q1yiso) = iso_map(&q1x, &q1y); - assert!(is_on_curve_iso(q0x, q0y)); - assert!(is_on_curve_iso(q1x, q1y)); - assert!(is_on_curve(q0xiso, q0yiso)); - assert!(is_on_curve(q1xiso, q1yiso)); - (q0xiso, q0yiso, q1xiso, q1yiso) - } - - // This tests the function sswu_3mod4 function according to - // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-J.9.1 with - // suite = BLS12381G1_XMD:SHA-256_SSWU_RO_ - // dst = QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_ - #[test] - fn test_sswu_3mod4() { - let msg = "".as_bytes(); - let (q0xiso, q0yiso, q1xiso, q1yiso) = test_sswu_3mod4_helper(msg); - assert_eq!(q0xiso.into_repr().0, [ - 15322189115692639998, - 15797359889106953011, - 5653489230086698368, - 4682126050798829791, - 11024924806559841173, - 1271084816147220853 - ]); - assert_eq!(q0yiso.into_repr().0, [ - 17067727968805097911, - 7418462616903021369, - 8864403726093601708, - 14513805319707135942, - 8131830758927404468, - 1074942866857687522 - ]); - assert_eq!(q1xiso.into_repr().0, [ - 7808298569491230620, - 7184018956363952831, - 13981477771596724781, - 18443703881190742655, - 4138169057032534528, - 1585271101563546387 - ]); - assert_eq!(q1yiso.into_repr().0, [ - 7824395264510227294, - 11246731451409989510, - 4236565643110496590, - 9890286780414566419, - 6932751967244965777, - 976070356284526495 - ]); - let msg = "abc".as_bytes(); - let (q0xiso, q0yiso, q1xiso, q1yiso) = test_sswu_3mod4_helper(msg); - assert_eq!(q0xiso.into_repr().0, [ - 12430049376656784768, - 16784989396329743852, - 14149281322662614863, - 15883688380205406658, - 2053710085736387474, - 1320739611337432253 - ]); - assert_eq!(q0yiso.into_repr().0, [ - 16146441685514193906, - 18107653483902884492, - 2715374782011144092, - 13650205344856941821, - 6439834167788999452, - 1047131531842720038 - ]); - assert_eq!(q1xiso.into_repr().0, [ - 8910236932580018916, - 7815904322292209096, - 7593225441770187758, - 11255819455150393731, - 11796170597050860460, - 1287740558521048781 - ]); - assert_eq!(q1yiso.into_repr().0, [ - 12692728337348062438, - 17769121624066068114, - 17879473399542176639, - 766305063492018676, - 17280931718342900840, - 2192215483010290 - ]); - let msg = "abcdef0123456789".as_bytes(); - let (q0xiso, q0yiso, q1xiso, q1yiso) = test_sswu_3mod4_helper(msg); - assert_eq!(q0xiso.into_repr().0, [ - 9041900009822400511, - 18050568042394074917, - 4183240265480474299, - 215533130473142672, - 9436959430308611144, - 613409310252999030 - ]); - assert_eq!(q0yiso.into_repr().0, [ - 4261986790105305230, - 14836003795461730496, - 3332638795667425986, - 15193945174579615310, - 1081864890664714785, - 806583583085425754 - ]); - assert_eq!(q1xiso.into_repr().0, [ - 17455435680279498862, - 15918940529203786130, - 13517413051990971646, - 3112484043422443391, - 11458656200237888898, - 1550391579706384980 - ]); - assert_eq!(q1yiso.into_repr().0, [ - 438849826323699359, - 12283480024969580770, - 4792612028906851749, - 7222655975100958127, - 14265215465550907273, - 1763448765852971514 - ]); - let msg = "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq".as_bytes(); - let (q0xiso, q0yiso, q1xiso, q1yiso) = test_sswu_3mod4_helper(msg); - assert_eq!(q0xiso.into_repr().0, [ - 10708545032665212688, - 17591047437115732803, - 10257152130940741089, - 15450987893913966100, - 4605628236715863395, - 918030106871241060 - ]); - assert_eq!(q0yiso.into_repr().0, [ - 17515780972724750437, - 3794819297212639744, - 14290165729092219587, - 5566163866753941733, - 15656906651893164327, - 372673852399079424 - ]); - assert_eq!(q1xiso.into_repr().0, [ - 10097535120791090553, - 15551609254877439630, - 10830478155963611755, - 12071872099383128523, - 17333194118490526774, - 452963290844057914 - ]); - assert_eq!(q1yiso.into_repr().0, [ - 6314778073248787380, - 940087490787061227, - 2483122288128477485, - 13885439155570656426, - 6916029826893712320, - 209856280269423280 - ]); - let msg = "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes(); - let (q0xiso, q0yiso, q1xiso, q1yiso) = test_sswu_3mod4_helper(msg); - assert_eq!(q0xiso.into_repr().0, [ - 8748476113528902904, - 7472129550841271360, - 3674716482422288788, - 11268616350755635339, - 9168862108066020144, - 934917407444125573 - ]); - assert_eq!(q0yiso.into_repr().0, [ - 8223791200044538547, - 6018860960006646637, - 1823901729006231578, - 7060918718893525758, - 1160335519914892552, - 1332798162118717528 - ]); - assert_eq!(q1xiso.into_repr().0, [ - 12854496189098119466, - 5157345485357217551, - 681098616738014507, - 13715717402073062672, - 6378441195789129883, - 661777149395142137 - ]); - assert_eq!(q1yiso.into_repr().0, [ - 15981086486121135807, - 2958272527530984821, - 9419624270969761554, - 15253123571016032668, - 15813118937382962177, - 184204487603727614 - ]); - } - - // This tests the function hash_to_curve function according to - // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-J.9.1 with - // suite = BLS12381G1_XMD:SHA-256_SSWU_RO_ - // dst = QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_ - #[test] - fn test_hash_to_curve() { - let msg = "".as_bytes(); - let dst = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_"; - let p = hash_to_curve(msg, &dst[..]); - assert_eq!(to_bytes(&p), vec![ - 133, 41, 38, 173, 210, 32, 123, 118, 202, 79, 165, 122, 135, 52, 65, 108, 141, 201, 94, - 36, 80, 23, 114, 200, 20, 39, 135, 0, 238, 214, 209, 228, 232, 207, 98, 217, 192, 157, - 176, 250, 195, 73, 97, 43, 117, 158, 121, 161 - ]); - // The point should have (in hex) - // P.x = 052926add2207b76ca4fa57a8734416c8dc95e24501772c8142787 - // 00eed6d1e4e8cf62d9c09db0fac349612b759e79a1 - // P.y = 08ba738453bfed09cb546dbb0783dbb3a5f1f566ed67bb6be0e8c6 - // 7e2e81a4cc68ee29813bb7994998f3eae0c9c6a265 - assert_eq!(p, from_coordinates_unchecked( - Fq::from_str("794311575721400831362957049303781044852006323422624111893352859557450008308620925451441746926395141598720928151969").unwrap(), - Fq::from_str("1343412193624222137939591894701031123123641958980729764240763391191550653712890272928110356903136085217047453540965").unwrap(), - Fq::one())); - let msg = "abc".as_bytes(); - let p = hash_to_curve(msg, &dst[..]); - assert_eq!(to_bytes(&p), vec![ - 131, 86, 123, 197, 239, 156, 105, 12, 42, 178, 236, 223, 106, 150, 239, 28, 19, 156, - 192, 178, 242, 132, 220, 160, 169, 167, 148, 51, 136, 164, 154, 58, 238, 102, 75, 165, - 55, 154, 118, 85, 211, 198, 137, 0, 190, 47, 105, 3 - ]); - // The point should have (in hex) - // P.x = 03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a794 - // 3388a49a3aee664ba5379a7655d3c68900be2f6903 - // P.y = 0b9c15f3fe6e5cf4211f346271d7b01c8f3b28be689c8429c85b67 - // af215533311f0b8dfaaa154fa6b88176c229f2885d - assert_eq!(p, from_coordinates_unchecked( - Fq::from_str("513738460217615943921285247703448567647875874745567372796164155472383127756567780059136521508428662765965997467907").unwrap(), - Fq::from_str("1786897908129645780825838873875416513994655004408749907941296449131605892957529391590865627492442562626458913769565").unwrap(), - Fq::one())); - let msg = "abcdef0123456789".as_bytes(); - let p = hash_to_curve(msg, &dst[..]); - assert_eq!(to_bytes(&p), vec![ - 145, 224, 176, 121, 222, 162, 154, 104, 240, 56, 62, 233, 79, 237, 27, 148, 9, 149, 39, - 36, 7, 227, 187, 145, 107, 191, 38, 140, 38, 61, 221, 87, 166, 162, 114, 0, 167, 132, - 203, 194, 72, 232, 79, 53, 124, 232, 45, 152 - ]); - // The point should have (in hex) - // P.x = 11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf26 - // 8c263ddd57a6a27200a784cbc248e84f357ce82d98 - // P.y = 03a87ae2caf14e8ee52e51fa2ed8eefe80f02457004ba4d486d6aa - // 1f517c0889501dc7413753f9599b099ebcbbd2d709 - assert_eq!(p, from_coordinates_unchecked( - Fq::from_str("2751628761372137084683207295437105268166375184027748372156952770986741873369176463286511518644061904904607431667096").unwrap(), - Fq::from_str("563036982304416203921640398061260377444881693369806087719971277317609936727208012968659302318886963927918562170633").unwrap(), - Fq::one())); - let msg = "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq".as_bytes(); - let p = hash_to_curve(msg, &dst[..]); - assert_eq!(to_bytes(&p), vec![ - 181, 246, 142, 170, 105, 59, 149, 204, 184, 82, 21, 220, 101, 250, 129, 3, 141, 105, - 98, 159, 112, 174, 238, 13, 15, 103, 124, 242, 34, 133, 231, 191, 88, 215, 203, 134, - 238, 254, 143, 46, 155, 195, 248, 203, 132, 250, 196, 136 - ]); - // The point should have (in hex) - // P.x = 15f68eaa693b95ccb85215dc65fa81038d69629f70aeee0d0f677c - // f22285e7bf58d7cb86eefe8f2e9bc3f8cb84fac488 - // P.y = 1807a1d50c29f430b8cafc4f8638dfeeadf51211e1602a5f184443 - // 076715f91bb90a48ba1e370edce6ae1062f5e6dd38 - assert_eq!(p, from_coordinates_unchecked( - Fq::from_str("3380432694887674439773082418192083720584748080704959172978586229921475315220434165460350679208315690319508336723080").unwrap(), - Fq::from_str("3698526739072864408749571082270628561764415577445404115596990919801523793138348254443092179877354467167123794222392").unwrap(), - Fq::one())); - let msg = "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes(); - let p = hash_to_curve(msg, &dst[..]); - assert_eq!(to_bytes(&p), vec![ - 136, 42, 171, 174, 139, 125, 237, 176, 231, 138, 235, 97, 154, 211, 191, 217, 39, 122, - 47, 119, 186, 127, 173, 32, 239, 106, 171, 220, 108, 49, 209, 155, 165, 166, 209, 34, - 131, 85, 50, 148, 193, 130, 92, 75, 60, 162, 220, 254 - ]); - // The point should have (in hex) - // P.x = 082aabae8b7dedb0e78aeb619ad3bfd9277a2f77ba7fad20ef6aab - // dc6c31d19ba5a6d12283553294c1825c4b3ca2dcfe - // P.y = 05b84ae5a942248eea39e1d91030458c40153f3b654ab7872d779a - // d1e942856a20c438e8d99bc8abfbf74729ce1f7ac8 - assert_eq!(p, from_coordinates_unchecked( - Fq::from_str("1256967425542823069694513550918025689490036478501181600525944653952846100887848729514132077573887342346961531624702").unwrap(), - Fq::from_str("880372082403694543476959909256504267215588055450016885103797700856746532134585942561958795215862304181527267736264").unwrap(), - Fq::one())); - } -} diff --git a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_g2hash.rs b/rust-src/concordium_base/src/curve_arithmetic/bls12_381_g2hash.rs deleted file mode 100644 index 7f2c0b07d..000000000 --- a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_g2hash.rs +++ /dev/null @@ -1,749 +0,0 @@ -use ff::{Field, PrimeField, SqrtField}; -use group::{CurveProjective, EncodedPoint}; -use pairing::bls12_381::{Fq, Fq2, FqRepr, G2Uncompressed, G2}; -use sha2::{Digest, Sha256}; -use std::{ - convert::TryInto, - io::{Cursor, Write}, -}; - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-3 -/// It follows the steps -/// 1. u = hash_to_field(msg, 2) -/// 2. Q0 = map_to_curve(u[0]) -/// 3. Q1 = map_to_curve(u[1]) -/// 4. R = Q0 + Q1 -/// 5. P = clear_cofactor(R) = h_eff * R # Clearing cofactor -/// 6. return P, -/// where the choices of hash_to_field, map_to_curve and h_eff are as described in https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-8.8.2. -pub fn hash_to_curve_g2(msg: &[u8], dst: &[u8]) -> G2 { - let (u0, u1) = hash_to_field_fq2(msg, dst); - - let q0 = map_to_curve_g2(u0); // This is on E, but not necessarily in G2 - let q1 = map_to_curve_g2(u1); // This is on E, but not necessarily in G2 - - let mut r = q0; - r.add_assign(&q1); // This is on E, but not necessarily in G2 - // Clearing cofactor with h_eff - clear_cofactor_g2(r) // This now guaranteed to be in G2 -} - -/// This is an inefficient method for clearing the cofactor. -/// Corresponds to multiplying by h_eff in https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-8.8.2 -/// A much faster equivalent implementation is available in https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-G.4 -fn clear_cofactor_g2(p: G2) -> G2 { - // h_eff = 0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551 - // it is not possible to use the implementation of mul_assign for G2 directly - // the implementation of scalar (i.e. Fr) reduces h_eff by |G2|, which gives - // equivalent results for points in G2, but not general points on the curve - // |G2| = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 - let h_eff_u64s: [u64; 9] = [ - 0x584c6a0ea91b3528, - 0x88e2a8e9145ad768, - 0x9986ff031508ffe1, - 0x329c2f178731db95, - 0x6d82bf015d1212b0, - 0x2ec0ec69d7477c1a, - 0xe954cbc06689f6a3, - 0x59894c0adebbf6b4, - 0xe8020005aaa95551, - ]; - let mut res = p; - res.mul_assign(0x0bc69f08f2ee75b3); - for i in h_eff_u64s.iter() { - for _ in 0..64 { - res.double(); - } - let mut next = p; - - next.mul_assign(*i); - res.add_assign(&next); - } - res -} - -fn map_to_curve_g2(u: Fq2) -> G2 { - let (x, y) = sswu(u); - let (x, y, z) = iso_map(x, y, Fq2::one()); - from_coordinates_unchecked(x, y, z) -} - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.6.2 -/// This is not the optimized version described in https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-G.2.3 -#[allow(clippy::many_single_char_names)] -fn sswu(u: Fq2) -> (Fq2, Fq2) { - let a = Fq2 { - c0: Fq::zero(), - c1: Fq::from_repr(FqRepr::from(240)).unwrap(), - }; - let b = Fq2 { - c0: Fq::from_repr(FqRepr::from(1012)).unwrap(), - c1: Fq::from_repr(FqRepr::from(1012)).unwrap(), - }; - let mut z = Fq2 { - c0: Fq::from_repr(FqRepr::from(2)).unwrap(), - c1: Fq::from_repr(FqRepr::from(1)).unwrap(), - }; - z.negate(); - - // Constants: - // 1. c1 = -B / A - let mut c1 = a; - c1 = c1.inverse().unwrap(); - c1.mul_assign(&b); - c1.negate(); - // 2. c2 = -1 / Z - let mut c2 = z.inverse().unwrap(); - c2.negate(); - - // all values above are constants - - // Steps: - // 1. tv1 = Z * u^2 - let mut tv1 = u; - tv1.square(); - tv1.mul_assign(&z); - // 2. tv2 = tv1^2 - let mut tv2 = tv1; - tv2.square(); - // 3. x1 = tv1 + tv2 - let mut x1 = tv1; - x1.add_assign(&tv2); - // 4. x1 = inv0(x1) - x1 = match x1.inverse() { - None => Fq2::zero(), - Some(x1inv) => x1inv, - }; - // 5. e1 = x1 == 0 - let e1 = x1.is_zero(); - // 6. x1 = x1 + 1 - x1.add_assign(&Fq2::one()); - // 7. x1 = CMOV(x1, c2, e1) # If (tv1 + tv2) == 0, set x1 = -1 / Z - if e1 { - x1 = c2; - } - // 8. x1 = x1 * c1 # x1 = (-B / A) * (1 + (1 / (Z^2 * u^4 + Z * u^2))) - x1.mul_assign(&c1); - // 9. gx1 = x1^2 - let mut gx1 = x1; - gx1.square(); - // 10. gx1 = gx1 + A - gx1.add_assign(&a); - // 11. gx1 = gx1 * x1 - gx1.mul_assign(&x1); - // 12. gx1 = gx1 + B # gx1 = g(x1) = x1^3 + A * x1 + B - gx1.add_assign(&b); - // 13. x2 = tv1 * x1 # x2 = Z * u^2 * x1 - let mut x2 = tv1; - x2.mul_assign(&x1); - // 14. tv2 = tv1 * tv2 - tv2.mul_assign(&tv1); - // 15. gx2 = gx1 * tv2 # gx2 = (Z * u^2)^3 * gx1 - let mut gx2 = gx1; - gx2.mul_assign(&tv2); - // 16. e2 = is_square(gx1) - let e2 = gx1.sqrt().is_some(); - // 17. x = CMOV(x2, x1, e2) # If is_square(gx1), x = x1, else x = x2 - // 18. y2 = CMOV(gx2, gx1, e2) # If is_square(gx1), y2 = gx1, else y2 = gx2 - let mut x = x2; - let mut y2 = gx2; - if e2 { - x = x1; - y2 = gx1; - } - // 19. y = sqrt(y2) - let mut y = y2.sqrt().unwrap(); - // 20. e3 = sgn0(u) == sgn0(y) # Fix sign of y - let e3 = sgn0(u) == sgn0(y); - // 21. y = CMOV(-y, y, e3) - if !e3 { - y.negate(); - } - // 22. return (x, y) - (x, y) -} - -/// The function sgn0 given at https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-4.1 -fn sgn0(x: Fq2) -> u64 { - let sign_0 = x.c0.into_repr().0[0] % 2; - let zero_0 = x.c0.is_zero(); - let sign_1 = x.c1.into_repr().0[0] % 2; - sign_0 | (zero_0 as u64 & sign_1) -} - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-5.4.1 -/// len_in_bytes is fixed to 256 -/// Domain separation string (dst) should be at most 255 bytes -fn expand_message_xmd(msg: &[u8], dst: &[u8]) -> [[u8; 32]; 8] { - // DST_prime = DST || I2OSP(len(DST), 1) - let mut dst_prime = dst.to_vec(); - dst_prime.push(dst.len().try_into().unwrap()); // panics if dst is more than 255 bytes - - // b_0 = H(msg_prime), msg_prime = Z_pad || msg || l_i_b_str || I2OSP(0, 1) || - // DST_prime - let mut h = Sha256::new(); - h.update(vec![0; 64]); // z_pad = I2OSP(0, 64), 64 is the input block size of Sha265 - h.update(msg); - h.update(vec![1, 0]); // l_i_b_str = I2OSP(256, 2) - h.update([0u8]); - h.update(&dst_prime); - let mut b_0: [u8; 32] = [0u8; 32]; - b_0.copy_from_slice(h.finalize().as_slice()); - - // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) - let mut h = Sha256::new(); - h.update(b_0); - h.update([1u8]); - h.update(&dst_prime); - - let mut b = [[0u8; 32]; 8]; // b[i] corresponds to b_i+1 in specification. - b[0].copy_from_slice(h.finalize().as_slice()); - - // compute remaining uniform bytes - for i in 1u8..8 { - // b_i = H(strxor(b_0, b_i-1) || I2OSP(i, 1) || DST_prime) - let mut h = Sha256::new(); - let xor: Vec = b_0 - .iter() - .zip(b[i as usize - 1].iter()) - .map(|(x, y)| x ^ y) - .collect(); - h.update(xor); - h.update([i + 1]); // offset as standard drops b_0 and returns index b_1-b_8 - h.update(&dst_prime); - b[i as usize].copy_from_slice(h.finalize().as_slice()); - } - - b -} - -/// Implements https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-3 -/// with the choice of expand_message being expand_message_xmd, as specified in -/// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-8.8.2. -fn hash_to_field_fq2(msg: &[u8], dst: &[u8]) -> (Fq2, Fq2) { - let b = expand_message_xmd(msg, dst); - let u0 = Fq2 { - c0: fq_from_bytes(&b[0], &b[1]), - c1: fq_from_bytes(&b[2], &b[3]), - }; - let u1 = Fq2 { - c0: fq_from_bytes(&b[4], &b[5]), - c1: fq_from_bytes(&b[6], &b[7]), - }; - (u0, u1) -} - -// Interpret input as integers (big endian) -// Return (left*2^256 + right) as Fq -fn fq_from_bytes(left_bytes: &[u8; 32], right_bytes: &[u8; 32]) -> Fq { - fn le_u64s_from_be_bytes(bytes: &[u8; 32]) -> Fq { - let mut digits = [0u64; 6]; - - for (place, chunk) in digits.iter_mut().zip(bytes.chunks(8).rev()) { - *place = u64::from_be_bytes(chunk.try_into().expect("Chunk Sie is always 8")) - } - - Fq::from_repr(FqRepr(digits)).expect("Only the leading 4 u64s are initialized") - } - - let two_to_256_fqrepr = [0u64, 0, 0, 0, 1, 0]; // 2^256 - let two_to_256_fq = Fq::from_repr(FqRepr(two_to_256_fqrepr)).expect("2^256 fits in modulus"); - - let mut left_fq = le_u64s_from_be_bytes(left_bytes); - let right_fq = le_u64s_from_be_bytes(right_bytes); - left_fq.mul_assign(&two_to_256_fq); // u_0[..32] * 2^256 - left_fq.add_assign(&right_fq); // u_0[32..] + u_0[32..] * 2^256 = u_0 - - left_fq -} - -/// Computes the 3-isogeny map for G2, specified in -/// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-E.3 -fn iso_map(x: Fq2, y: Fq2, z: Fq2) -> (Fq2, Fq2, Fq2) { - // Compute Z^2i for i = 1,...,15 - let mut z_pow_2i: [Fq2; 15] = [z; 15]; - z_pow_2i[0].square(); // Z^2 - z_pow_2i[1] = z_pow_2i[0]; - z_pow_2i[1].square(); // Z^4 - let mut z_ = z_pow_2i[1]; - z_.mul_assign(&z_pow_2i[0]); - z_pow_2i[2] = z_; // Z^6 - z_pow_2i[3] = z_pow_2i[1]; - z_pow_2i[3].square(); // Z^8 - for i in 0..3 { - // Z^10, Z^12, Z^14, - z_ = z_pow_2i[3 + i]; - z_.mul_assign(&z_pow_2i[0]); - z_pow_2i[4 + i] = z_; - } - z_pow_2i[7] = z_pow_2i[3]; - z_pow_2i[7].square(); // Z^16 - for i in 0..7 { - // Z^18, Z^20, Z^22, Z^24, Z^26, Z^28, Z^30, - z_ = z_pow_2i[7 + i]; - z_.mul_assign(&z_pow_2i[0]); - z_pow_2i[8 + i] = z_; - } - - let x_num = horner(&K1, &z_pow_2i, &x); - - let x_den_ = horner(&K2, &z_pow_2i, &x); - let mut x_den = z_pow_2i[0]; - x_den.mul_assign(&x_den_); - - let y_num_ = horner(&K3, &z_pow_2i, &x); - let mut y_num = y; - y_num.mul_assign(&y_num_); - - let y_den_ = horner(&K4, &z_pow_2i, &x); - let mut y_den = z_pow_2i[0]; - y_den.mul_assign(&z); - y_den.mul_assign(&y_den_); - - let mut z_jac = x_den; - z_jac.mul_assign(&y_den); - let mut x_jac = x_num; - x_jac.mul_assign(&y_den); - x_jac.mul_assign(&z_jac); - let mut z_jac_pow2 = z_jac; - z_jac_pow2.square(); - let mut y_jac = y_num; - y_jac.mul_assign(&x_den); - y_jac.mul_assign(&z_jac_pow2); - - (x_jac, y_jac, z_jac) -} - -// Constants for the 3-isogeny map -const K1: [[[u64; 6]; 2]; 4] = [ - [ - [ - 0x6238aaaaaaaa97d6, - 0x5c2638e343d9c71c, - 0x88b58423c50ae15d, - 0x32c52d39fd3a042a, - 0xbb5b7a9a47d7ed85, - 0x5c759507e8e333e, - ], - [ - 0x6238aaaaaaaa97d6, - 0x5c2638e343d9c71c, - 0x88b58423c50ae15d, - 0x32c52d39fd3a042a, - 0xbb5b7a9a47d7ed85, - 0x5c759507e8e333e, - ], - ], - [[0, 0, 0, 0, 0, 0], [ - 0x26a9ffffffffc71a, - 0x1472aaa9cb8d5555, - 0x9a208c6b4f20a418, - 0x984f87adf7ae0c7f, - 0x32126fced787c88f, - 0x11560bf17baa99bc, - ]], - [ - [ - 0x26a9ffffffffc71e, - 0x1472aaa9cb8d5555, - 0x9a208c6b4f20a418, - 0x984f87adf7ae0c7f, - 0x32126fced787c88f, - 0x11560bf17baa99bc, - ], - [ - 0x9354ffffffffe38d, - 0x0a395554e5c6aaaa, - 0xcd104635a790520c, - 0xcc27c3d6fbd7063f, - 0x190937e76bc3e447, - 0x8ab05f8bdd54cde, - ], - ], - [ - [ - 0x88e2aaaaaaaa5ed1, - 0x7098e38d0f671c71, - 0x22d6108f142b8575, - 0xcb14b4e7f4e810aa, - 0xed6dea691f5fb614, - 0x171d6541fa38ccfa, - ], - [0, 0, 0, 0, 0, 0], - ], -]; - -const K2: [[[u64; 6]; 2]; 3] = [ - [[0, 0, 0, 0, 0, 0], [ - 0xb9feffffffffaa63, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ]], - [[0xc, 0, 0, 0, 0, 0], [ - 0xb9feffffffffaa9f, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ]], - [[1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], -]; - -const K3: [[[u64; 6]; 2]; 4] = [ - [ - [ - 0x12cfc71c71c6d706, - 0xfc8c25ebf8c92f68, - 0xf54439d87d27e500, - 0x0f7da5d4a07f649b, - 0x59a4c18b076d1193, - 0x1530477c7ab4113b, - ], - [ - 0x12cfc71c71c6d706, - 0xfc8c25ebf8c92f68, - 0xf54439d87d27e500, - 0x0f7da5d4a07f649b, - 0x59a4c18b076d1193, - 0x1530477c7ab4113b, - ], - ], - [[0, 0, 0, 0, 0, 0], [ - 0x6238aaaaaaaa97be, - 0x5c2638e343d9c71c, - 0x88b58423c50ae15d, - 0x32c52d39fd3a042a, - 0xbb5b7a9a47d7ed85, - 0x5c759507e8e333e, - ]], - [ - [ - 0x26a9ffffffffc71c, - 0x1472aaa9cb8d5555, - 0x9a208c6b4f20a418, - 0x984f87adf7ae0c7f, - 0x32126fced787c88f, - 0x11560bf17baa99bc, - ], - [ - 0x9354ffffffffe38f, - 0x0a395554e5c6aaaa, - 0xcd104635a790520c, - 0xcc27c3d6fbd7063f, - 0x190937e76bc3e447, - 0x8ab05f8bdd54cde, - ], - ], - [ - [ - 0xe1b371c71c718b10, - 0x4e79097a56dc4bd9, - 0xb0e977c69aa27452, - 0x761b0f37a1e26286, - 0xfbf7043de3811ad0, - 0x124c9ad43b6cf79b, - ], - [0, 0, 0, 0, 0, 0], - ], -]; - -const K4: [[[u64; 6]; 2]; 4] = [ - [ - [ - 0xb9feffffffffa8fb, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ], - [ - 0xb9feffffffffa8fb, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ], - ], - [[0, 0, 0, 0, 0, 0], [ - 0xb9feffffffffa9d3, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ]], - [[0x12, 0x0, 0x0, 0x0, 0x0, 0x0], [ - 0xb9feffffffffaa99, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ]], - [[1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], -]; - -fn horner(coefficients: &[[[u64; 6]; 2]], z_powers: &[Fq2], variable: &Fq2) -> Fq2 { - fn fq2_from_u64s(u64s: [[u64; 6]; 2]) -> Fq2 { - // unwrapping the Ki constants never fails: - Fq2 { - c0: Fq::from_repr(FqRepr(u64s[0])).unwrap(), - c1: Fq::from_repr(FqRepr(u64s[1])).unwrap(), - } - } - - let clen = coefficients.len(); - let mut res = fq2_from_u64s(coefficients[clen - 1]); - // skip the last coefficient since we already used it - for (coeff, pow) in coefficients.iter().rev().skip(1).zip(z_powers.iter()) { - res.mul_assign(variable); - let mut coeff = fq2_from_u64s(*coeff); - coeff.mul_assign(pow); - res.add_assign(&coeff); - } - res -} - -// Returns a point on E1 with coordinates x,y,z. -// CAREFUL! This point is NOT guaranteed to be in the correct order subgroup -// To get the point into the correct order subgroup, clear cofactor. -#[inline] -fn from_coordinates_unchecked(x: Fq2, y: Fq2, z: Fq2) -> G2 { - if z.is_zero() { - G2::zero() - } else { - let z_inv = z.inverse().unwrap(); - let mut z_inv2 = z_inv; - z_inv2.square(); - let mut p_x = x; - p_x.mul_assign(&z_inv2); - let mut p_y = y; - p_y.mul_assign(&z_inv); - p_y.mul_assign(&z_inv2); - - let mut uncompress_point = G2Uncompressed::empty(); - let mut cursor = Cursor::new(uncompress_point.as_mut()); - - for digit in p_x.c1.into_repr().as_ref().iter().rev() { - cursor - .write_all(&digit.to_be_bytes()) - .expect("This write will always succeed."); - } - for digit in p_x.c0.into_repr().as_ref().iter().rev() { - cursor - .write_all(&digit.to_be_bytes()) - .expect("This write will always succeed."); - } - for digit in p_y.c1.into_repr().as_ref().iter().rev() { - cursor - .write_all(&digit.to_be_bytes()) - .expect("This write will always succeed."); - } - for digit in p_y.c0.into_repr().as_ref().iter().rev() { - cursor - .write_all(&digit.to_be_bytes()) - .expect("This write will always succeed."); - } - - // The below is safe, since xiso, yiso, z are in Fq. - // The into_affine_unchecked() used below can fail if - // at least one of the bits representing 2^5, 2^6 or 2^7 in the first entry of - // the `uncompress_point` are set, but this will not happen. - // c1 lies in Fq, where - // q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787, - // and since 27 * 2^(47*8) > q, the first entry of - // `uncompress_point` will always be < 27 < 2^5, since this entry - // represents the number of 2^(47*8)'s. - let res = uncompress_point.into_affine_unchecked(); - G2::from(res.expect("Should not happen, since input coordinates are in Fq2.")) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_hash_to_field_fq2() { - // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-J.10.1 - let dst = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_"; - - { - // msg = - // u[0] = 03dbc2cce174e91ba93cbb08f26b917f98194a2ea08d1cce75b2b9 - // cc9f21689d80bd79b594a613d0a68eb807dfdc1cf8 - // + I * 05a2acec64114845711a54199ea339abd125ba38253b70a92c876d - // f10598bd1986b739cad67961eb94f7076511b3b39a - // u[1] = 02f99798e8a5acdeed60d7e18e9120521ba1f47ec090984662846b - // c825de191b5b7641148c0dbc237726a334473eee94 - // + I * 145a81e418d4010cc027a68f14391b30074e89e60ee7a22f87217b - // 2f6eb0c4b94c9115b436e6fa4607e95a98de30a435 - let msg = b""; - let (u0, u1) = hash_to_field_fq2(msg, dst); - assert_eq!( - u0, - Fq2{ - c0: Fq::from_str("593868448310005448561172252387029516360409945786457439875974315031640021389835649561235021338510064922970633805048").unwrap(), - c1: Fq::from_str("867375309489067512797459860887365951877054038763818448057326190302701649888849997836339069389536967202878289851290").unwrap()} - ); - assert_eq!( - u1, - Fq2{ - c0: Fq::from_str("457889704519948843474026022562641969443315715595459159112874498082953431971323809145630315884223143822925947137684").unwrap(), - c1: Fq::from_str("3132697209754082586339430915081913810572071485832539443682634025529375380328136128542015469873094481703191673087029").unwrap()} - ); - } - - { - // msg = abc - // u[0] = 15f7c0aa8f6b296ab5ff9c2c7581ade64f4ee6f1bf18f55179ff44 - // a2cf355fa53dd2a2158c5ecb17d7c52f63e7195771 - // + I * 01c8067bf4c0ba709aa8b9abc3d1cef589a4758e09ef53732d670f - // d8739a7274e111ba2fcaa71b3d33df2a3a0c8529dd - // u[1] = 187111d5e088b6b9acfdfad078c4dacf72dcd17ca17c82be35e79f - // 8c372a693f60a033b461d81b025864a0ad051a06e4 - // + I * 08b852331c96ed983e497ebc6dee9b75e373d923b729194af8e72a - // 051ea586f3538a6ebb1e80881a082fa2b24df9f566 - let msg = b"abc"; - let (u0, u1) = hash_to_field_fq2(msg, dst); - assert_eq!( - u0, - Fq2{ - c0: Fq::from_str("3381151350286428005095780827831774583653641216459357823974407145557165174365389989442078766443621078367363453769585").unwrap(), - c1: Fq::from_str("274174695370444263853418070745339731640467919355184108253716879519695397069963034977795744692362177212201505728989").unwrap()} - ); - assert_eq!( - u1, - Fq2{ - c0: Fq::from_str("3761918608077574755256083960277010506684793456226386707192711779006489497410866269311252402421709839991039401264868").unwrap(), - c1: Fq::from_str("1342131492846344403298252211066711749849099599627623100864413228392326132610002371925674088601653350525231531947366").unwrap()} - ); - } - } - - #[test] - fn test_hash_to_curve_g2() { - // Test vectors are from https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#appendix-J.10.1 - let dst = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_"; - { - // msg = - // P.x = - // 0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a - // + I * - // 05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d - // P.y = - // 0503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92 - // + I * - // 12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d6 - let msg = b""; - let p_should_be = from_coordinates_unchecked( - Fq2{ - c0: Fq::from_str("193548053368451749411421515628510806626565736652086807419354395577367693778571452628423727082668900187036482254730").unwrap(), - c1: Fq::from_str("891930009643099423308102777951250899694559203647724988361022851024990473423938537113948850338098230396747396259901").unwrap() - }, - Fq2{ - c0: Fq::from_str("771717272055834152378281705972671257005357145478800908373659404991537354153455452961747174765859335819766715637138").unwrap(), - c1: Fq::from_str("2810310118582126634041133454180705304393079139103252956502404531123692847658283858246402311867775854528543237781718").unwrap() - }, - Fq2::one() - ); - let p = hash_to_curve_g2(msg, dst); - assert_eq!(p, p_should_be); - } - { - // msg = abc - // P.x = 02c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e6 - // + I * 139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd8 - // P.y = 1787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48 - // + I * 00aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd16 - let msg = b"abc"; - let p_should_be = from_coordinates_unchecked( - Fq2{ - c0: Fq::from_str("424958340463073975547762735517193206833255107941790909009827635556634414746056077714431786321247871628515967727334").unwrap(), - c1: Fq::from_str("3018679803970127877262826393814472528557413504329194740495363852840690589001358162447917674089074634504498585239512").unwrap() - }, - Fq2{ - c0: Fq::from_str("3621308185128395459888995526527127556614768604472132176060423302734876099689739385100475320409412954617897892887112").unwrap(), - c1: Fq::from_str("102447784096837908713257069727879782642075240724579670654226801345708452018676587771714457671432122751958633012502").unwrap() - }, - Fq2::one() - ); - let p = hash_to_curve_g2(msg, dst); - assert_eq!(p, p_should_be); - } - { - // msg = abcdef0123456789 - // P.x = 121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd0 - // + I * 190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c - // P.y = 05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8 - // + I * 0bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be - let msg = b"abcdef0123456789"; - let p_should_be = from_coordinates_unchecked( - Fq2{ - c0: Fq::from_str("2785790728239146617702443308248535381016035748520698399690132325213972292102741627498014391457605127656937478044880").unwrap(), - c1: Fq::from_str("3855709393631831880910167818276435187147963371126198799654803099743427431977934703201153169947378798970358200024876").unwrap() - }, - Fq2{ - c0: Fq::from_str("821938378705205565995357931232097952117504537366318395539093959918654729488074273868834599496909844419980823111624").unwrap(), - c1: Fq::from_str("1802420335575779950982935580421454302087567926385222707947527353462942499437987207287862072369052390195154530059198").unwrap() - }, - Fq2::one() - ); - let p = hash_to_curve_g2(msg, dst); - assert_eq!(p, p_should_be); - } - { - // msg = q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq - // P.x = 19a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da - // + I * 0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb91 - // P.y = 14f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192 - // + I * 09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e5662 - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; - let p_should_be = from_coordinates_unchecked( - Fq2{ - c0: Fq::from_str("3949041098513688455491231180749724794697192943196730030853285011755806989731870696216017360514887069032515603535834").unwrap(), - c1: Fq::from_str("1416893694506131976809002935212216317132941942570763849323065381335907430566747765697423320407614734575486820936593").unwrap() - }, - Fq2{ - c0: Fq::from_str("3227453710863835032992962605851449401391399355135442728893790186263669279022343042444878900124369614767241382891922").unwrap(), - c1: Fq::from_str("1498738834073759871886466122933996764471889514532827927202777922460876335493588931070034160657995151627624577390178").unwrap() - }, - Fq2::one() - ); - let p = hash_to_curve_g2(msg, dst); - assert_eq!(p, p_should_be); - } - { - // msg = - // a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - // P.x = - // 01a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f62534 - // + I * - // 11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d01569 - // P.y = - // 0b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e - // + I * - // 03a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab52 - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let p_should_be = from_coordinates_unchecked( - Fq2{ - c0: Fq::from_str("254155017921606149907129844368549510385368618440139550318910532874259603395336903946742408725761795820224536519988").unwrap(), - c1: Fq::from_str("2768431459296730426779166218544149791601585986233130583011501727704972362141149700714785450629498506208393873593705").unwrap() - }, - Fq2{ - c0: Fq::from_str("1755339344744337457318565116062025669984750617937721245220711425551575490663761638802010265668157125441634554205566").unwrap(), - c1: Fq::from_str("560643043433789571968941329642646582974304556331567393300563909451776257854214387388500126524984624222885267024722").unwrap() - }, - Fq2::one() - ); - let p = hash_to_curve_g2(msg, dst); - assert_eq!(p, p_should_be); - } - } -} diff --git a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_instance.rs b/rust-src/concordium_base/src/curve_arithmetic/bls12_381_instance.rs deleted file mode 100644 index 95d9d8ce4..000000000 --- a/rust-src/concordium_base/src/curve_arithmetic/bls12_381_instance.rs +++ /dev/null @@ -1,474 +0,0 @@ -use super::{bls12_381_g1hash::*, bls12_381_g2hash::*, *}; -use byteorder::ReadBytesExt; -use group::{CurveAffine, CurveProjective, EncodedPoint}; -use pairing::{ - bls12_381::{ - Bls12, Fq, FqRepr, Fr, FrRepr, G1Affine, G1Compressed, G1Prepared, G2Affine, G2Compressed, - G2Prepared, G1, G2, - }, - Engine, PairingCurveAffine, -}; -use rand::*; - -const HASH_TO_GROUP_G1_DST: &[u8; 55] = b"CONCORDIUM-hashtoG1-with-BLS12381G1_XMD:SHA-256_SSWU_RO"; -const HASH_TO_GROUP_G2_DST: &[u8; 55] = b"CONCORDIUM-hashtoG2-with-BLS12381G2_XMD:SHA-256_SSWU_RO"; - -// Helper function for both G1 and G2 instances. -fn scalar_from_bytes_helper>(bytes: A) -> Fr { - // Traverse at most 4 8-byte chunks, for a total of 256 bits. - // The top-most two bits in the last chunk are set to 0. - let mut fr = [0u64; 4]; - for (i, chunk) in bytes.as_ref().chunks(8).take(4).enumerate() { - let mut v = [0u8; 8]; - v[..chunk.len()].copy_from_slice(chunk); - fr[i] = u64::from_le_bytes(v); - } - // unset two topmost bits in the last u64 limb. - fr[3] &= !(1u64 << 63 | 1u64 << 62); - ::from_repr(FrRepr(fr)) - .expect("The scalar with top two bits erased should be valid.") -} - -impl Field for F { - fn random(rng: &mut R) -> Self { Self::random(rng) } - - fn zero() -> Self { Self::zero() } - - fn one() -> Self { Self::one() } - - fn is_zero(&self) -> bool { Self::is_zero(self) } - - fn square(&mut self) { self.square() } - - fn double(&mut self) { self.double() } - - fn negate(&mut self) { self.negate() } - - fn add_assign(&mut self, other: &Self) { self.add_assign(other) } - - fn sub_assign(&mut self, other: &Self) { self.sub_assign(other) } - - fn mul_assign(&mut self, other: &Self) { self.mul_assign(other) } - - fn inverse(&self) -> Option { self.inverse() } -} - -impl From for CurveDecodingError { - fn from(e: ff::PrimeFieldDecodingError) -> Self { - let ff::PrimeFieldDecodingError::NotInField(msg) = e; - CurveDecodingError::NotInField(msg) - } -} - -impl PrimeField for Fr { - const CAPACITY: u32 = ::CAPACITY; - const NUM_BITS: u32 = ::NUM_BITS; - - fn into_repr(self) -> Vec { ::into_repr(&self).0.to_vec() } - - fn from_repr(limbs: &[u64]) -> Result { - let l4: [u64; 4] = limbs - .try_into() - .map_err(|_| CurveDecodingError::NotInField(format!("{:?}", limbs)))?; - let res = ::from_repr(FrRepr(l4))?; - Ok(res) - } -} - -impl PrimeField for Fq { - const CAPACITY: u32 = ::CAPACITY; - const NUM_BITS: u32 = ::NUM_BITS; - - fn into_repr(self) -> Vec { ::into_repr(&self).0.to_vec() } - - fn from_repr(limbs: &[u64]) -> Result { - let l6: [u64; 6] = limbs - .try_into() - .map_err(|_| CurveDecodingError::NotInField(format!("{:?}", limbs)))?; - let res = ::from_repr(FqRepr(l6))?; - Ok(res) - } -} - -impl Curve for G2 { - type MultiExpType = GenericMultiExp; - type Scalar = Fr; - - const GROUP_ELEMENT_LENGTH: usize = 96; - const SCALAR_LENGTH: usize = 32; - - fn zero_point() -> Self { G2::zero() } - - fn one_point() -> Self { G2::one() } - - fn inverse_point(&self) -> Self { - let mut x = *self; - x.negate(); - x - } - - fn is_zero_point(&self) -> bool { self.is_zero() } - - fn double_point(&self) -> Self { - let mut x = *self; - x.double(); - x - } - - fn plus_point(&self, other: &Self) -> Self { - let mut x = *self; - x.add_assign(other); - x - } - - fn minus_point(&self, other: &Self) -> Self { - let mut x = *self; - x.sub_assign(other); - x - } - - fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self { - let s = *scalar; - let mut p = *self; - p.mul_assign(s); - p - } - - #[inline(always)] - fn scalar_from_u64(n: u64) -> Self::Scalar { - ::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") - } - - #[inline(always)] - fn scalar_from_bytes>(bytes: A) -> Self::Scalar { - scalar_from_bytes_helper(bytes) - } - - fn bytes_to_curve_unchecked(bytes: &mut R) -> anyhow::Result { - let mut g = G2Compressed::empty(); - bytes.read_exact(g.as_mut())?; - Ok(g.into_affine_unchecked()?.into_projective()) - } - - fn generate(csprng: &mut T) -> Self { G2::random(csprng) } - - fn generate_scalar(csprng: &mut T) -> Self::Scalar { ::random(csprng) } - - fn hash_to_group(b: &[u8]) -> Self { hash_to_curve_g2(b, HASH_TO_GROUP_G2_DST) } -} - -impl Curve for G1 { - type MultiExpType = GenericMultiExp; - type Scalar = Fr; - - const GROUP_ELEMENT_LENGTH: usize = 48; - const SCALAR_LENGTH: usize = 32; - - fn zero_point() -> Self { G1::zero() } - - fn one_point() -> Self { G1::one() } - - fn inverse_point(&self) -> Self { - let mut x = *self; - x.negate(); - x - } - - fn is_zero_point(&self) -> bool { self.is_zero() } - - fn double_point(&self) -> Self { - let mut x = *self; - x.double(); - x - } - - fn plus_point(&self, other: &Self) -> Self { - let mut x = *self; - x.add_assign(other); - x - } - - fn minus_point(&self, other: &Self) -> Self { - let mut x = *self; - x.sub_assign(other); - x - } - - fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self { - let s = *scalar; - let mut p = *self; - p.mul_assign(s); - p - } - - #[inline(always)] - fn scalar_from_u64(n: u64) -> Self::Scalar { - ::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") - } - - #[inline(always)] - fn scalar_from_bytes>(bytes: A) -> Self::Scalar { - scalar_from_bytes_helper(bytes) - } - - fn bytes_to_curve_unchecked(bytes: &mut R) -> anyhow::Result { - let mut g = G1Compressed::empty(); - bytes.read_exact(g.as_mut())?; - Ok(g.into_affine_unchecked()?.into_projective()) - } - - fn generate(csprng: &mut T) -> Self { G1::random(csprng) } - - fn generate_scalar(csprng: &mut T) -> Self::Scalar { ::random(csprng) } - - fn hash_to_group(bytes: &[u8]) -> Self { hash_to_curve(bytes, HASH_TO_GROUP_G1_DST) } -} - -impl Curve for G1Affine { - type MultiExpType = GenericMultiExp; - type Scalar = Fr; - - const GROUP_ELEMENT_LENGTH: usize = 48; - const SCALAR_LENGTH: usize = 32; - - fn zero_point() -> Self { G1Affine::zero() } - - fn one_point() -> Self { G1Affine::one() } - - fn inverse_point(&self) -> Self { - let mut x = self.into_projective(); - x.negate(); - x.into_affine() - } - - fn is_zero_point(&self) -> bool { self.is_zero() } - - fn double_point(&self) -> Self { - let mut x = self.into_projective(); - x.double(); - x.into_affine() - } - - fn plus_point(&self, other: &Self) -> Self { - let mut x = self.into_projective(); - x.add_assign_mixed(other); - x.into_affine() - } - - fn minus_point(&self, other: &Self) -> Self { - let mut x = self.into_projective(); - x.sub_assign(&other.into_projective()); - x.into_affine() - } - - fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self { - let s = *scalar; - self.mul(s).into_affine() - } - - fn scalar_from_u64(n: u64) -> Self::Scalar { - ::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") - } - - #[inline(always)] - fn scalar_from_bytes>(bytes: A) -> Self::Scalar { - scalar_from_bytes_helper(bytes) - } - - fn bytes_to_curve_unchecked(bytes: &mut R) -> anyhow::Result { - let mut g = G1Compressed::empty(); - bytes.read_exact(g.as_mut())?; - Ok(g.into_affine_unchecked()?) - } - - fn generate(csprng: &mut T) -> Self { G1::random(csprng).into_affine() } - - fn generate_scalar(csprng: &mut T) -> Self::Scalar { ::random(csprng) } - - fn hash_to_group(b: &[u8]) -> Self { hash_to_curve(b, HASH_TO_GROUP_G1_DST).into_affine() } -} - -impl Curve for G2Affine { - type MultiExpType = GenericMultiExp; - type Scalar = Fr; - - const GROUP_ELEMENT_LENGTH: usize = 96; - const SCALAR_LENGTH: usize = 32; - - fn zero_point() -> Self { G2Affine::zero() } - - fn one_point() -> Self { G2Affine::one() } - - fn inverse_point(&self) -> Self { - let mut x = self.into_projective(); - x.negate(); - x.into_affine() - } - - fn is_zero_point(&self) -> bool { self.is_zero() } - - fn double_point(&self) -> Self { - let mut x = self.into_projective(); - x.double(); - x.into_affine() - } - - fn plus_point(&self, other: &Self) -> Self { - let mut x = self.into_projective(); - x.add_assign_mixed(other); - x.into_affine() - } - - fn minus_point(&self, other: &Self) -> Self { - let mut x = self.into_projective(); - x.sub_assign(&other.into_projective()); - x.into_affine() - } - - fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self { - let s = *scalar; - self.mul(s).into_affine() - } - - fn scalar_from_u64(n: u64) -> Self::Scalar { - ::from_repr(FrRepr::from(n)).expect("Every u64 is representable.") - } - - #[inline(always)] - fn scalar_from_bytes>(bytes: A) -> Self::Scalar { - scalar_from_bytes_helper(bytes) - } - - fn bytes_to_curve_unchecked(bytes: &mut R) -> anyhow::Result { - let mut g = G2Compressed::empty(); - bytes.read_exact(g.as_mut())?; - Ok(g.into_affine_unchecked()?) - } - - fn generate(csprng: &mut T) -> Self { G2::random(csprng).into_affine() } - - fn generate_scalar(csprng: &mut T) -> Self::Scalar { ::random(csprng) } - - fn hash_to_group(b: &[u8]) -> Self { hash_to_curve_g2(b, HASH_TO_GROUP_G2_DST).into_affine() } -} - -impl Pairing for Bls12 { - type G1 = ::G1; - type G1Prepared = G1Prepared; - type G2 = ::G2; - type G2Prepared = G2Prepared; - type ScalarField = Fr; - type TargetField = ::Fqk; - - #[inline(always)] - fn g1_prepare(g: &Self::G1) -> Self::G1Prepared { g.into_affine().prepare() } - - #[inline(always)] - fn g2_prepare(g: &Self::G2) -> Self::G2Prepared { g.into_affine().prepare() } - - #[inline(always)] - fn miller_loop<'a, I>(i: I) -> Self::TargetField - where - I: IntoIterator, { - ::miller_loop(i) - } - - #[inline(always)] - fn final_exponentiation(x: &Self::TargetField) -> Option { - ::final_exponentiation(x) - } - - #[inline(always)] - fn generate_scalar(csprng: &mut T) -> Self::ScalarField { Fr::random(csprng) } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::common::*; - use std::io::Cursor; - - // Check that scalar_from_bytes_helper works on small values. - #[test] - fn scalar_from_bytes_small() { - let mut rng = rand::thread_rng(); - for _ in 0..1000 { - let n = ::random(&mut rng); - let mut bytes = to_bytes(&n); - bytes.reverse(); - println!("bytes: {:?}", bytes[31]); - let m = scalar_from_bytes_helper(&bytes); - // Make sure that n and m only differ in the topmost bits; - // `scalar_from_bytes_helper` resets the topmost bits to zeros. - let n = n.into_repr(); - let m = m.into_repr(); - let mask = !(1u64 << 63 | 1u64 << 62); - assert_eq!(n[0], m[0], "First limb."); - assert_eq!(n[1], m[1], "Second limb."); - assert_eq!(n[2], m[2], "Third limb."); - assert_eq!(n[3] & mask, m[3], "Fourth limb with top bit masked."); - } - } - - macro_rules! macro_test_scalar_byte_conversion { - ($function_name:ident, $p:path) => { - #[test] - pub fn $function_name() { - let mut csprng = thread_rng(); - for _ in 0..1000 { - let scalar = <$p>::generate_scalar(&mut csprng); - let scalar_res = serialize_deserialize(&scalar); - assert!(scalar_res.is_ok()); - assert_eq!(scalar, scalar_res.unwrap()); - } - } - }; - } - - macro_rules! macro_test_group_byte_conversion { - ($function_name:ident, $p:path) => { - #[test] - pub fn $function_name() { - let mut csprng = thread_rng(); - for _ in 0..1000 { - let curve = <$p>::generate(&mut csprng); - let curve_res = serialize_deserialize(&curve); - assert!(curve_res.is_ok()); - assert_eq!(curve, curve_res.unwrap()); - } - } - }; - } - - macro_rules! macro_test_group_byte_conversion_unchecked { - ($function_name:ident, $p:path) => { - #[test] - pub fn $function_name() { - let mut csprng = thread_rng(); - for _ in 0..1000 { - let curve = <$p>::generate(&mut csprng); - let bytes = to_bytes(&curve); - let curve_res = <$p>::bytes_to_curve_unchecked(&mut Cursor::new(&bytes)); - assert!(curve_res.is_ok()); - assert_eq!(curve, curve_res.unwrap()); - } - } - }; - } - - macro_test_scalar_byte_conversion!(sc_bytes_conv_g1, G1); - macro_test_scalar_byte_conversion!(sc_bytes_conv_g2, G2); - macro_test_scalar_byte_conversion!(sc_bytes_conv_g1_affine, G1Affine); - macro_test_scalar_byte_conversion!(sc_bytes_conv_g2_affine, G2Affine); - macro_test_scalar_byte_conversion!(sc_bytes_conv_bls12, Bls12); - - macro_test_group_byte_conversion!(curve_bytes_conv_g1, G1); - macro_test_group_byte_conversion!(curve_bytes_conv_g2, G2); - macro_test_group_byte_conversion!(curve_bytes_conv_g1_affine, G1Affine); - macro_test_group_byte_conversion!(curve_bytes_conv_g2_affine, G2Affine); - - macro_test_group_byte_conversion_unchecked!(u_curve_bytes_conv_g1, G1); - macro_test_group_byte_conversion_unchecked!(u_curve_bytes_conv_g2, G2); - macro_test_group_byte_conversion_unchecked!(u_curve_bytes_conv_g1_affine, G1Affine); - macro_test_group_byte_conversion_unchecked!(u_curve_bytes_conv_g2_affine, G2Affine); -} diff --git a/rust-src/concordium_base/src/curve_arithmetic/ed25519_instance.rs b/rust-src/concordium_base/src/curve_arithmetic/ed25519_instance.rs index eeb16550d..f68e80f93 100644 --- a/rust-src/concordium_base/src/curve_arithmetic/ed25519_instance.rs +++ b/rust-src/concordium_base/src/curve_arithmetic/ed25519_instance.rs @@ -1,4 +1,4 @@ -use super::{Curve, Field, MultiExp, PrimeField}; +use super::{field_adapters::FFField, Curve, CurveDecodingError, Field, MultiExp, PrimeField}; use crate::common::{Buffer, Deserial, Serial}; use byteorder::{ByteOrder, LittleEndian}; use curve25519_dalek::{ @@ -7,81 +7,35 @@ use curve25519_dalek::{ scalar::Scalar, traits::{Identity, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}, }; -use std::{ - borrow::Borrow, - ops::{AddAssign, MulAssign, Neg, SubAssign}, -}; - -/// A wrapper to make it possible to implement external traits -/// and to avoid clashes with blacket implementations. -#[derive(Clone, Copy, Debug, PartialEq, Eq, derive_more::From)] -pub struct RistrettoScalar(Scalar); +use sha2::Sha512; +use std::{borrow::Borrow, result::Result}; -impl Serial for RistrettoScalar { +impl Serial for Scalar { fn serial(&self, out: &mut B) { - let res: &[u8; 32] = self.0.as_bytes(); + let res: &[u8; 32] = self.as_bytes(); out.write_all(res) .expect("Writing to a buffer should not fail."); } } -impl Deserial for RistrettoScalar { +impl Deserial for Scalar { fn deserial(source: &mut R) -> crate::common::ParseResult { let mut buf: [u8; 32] = [0; 32]; source.read_exact(&mut buf)?; - let res = Scalar::from_canonical_bytes(buf).ok_or(anyhow::anyhow!( + let res: Option<_> = Scalar::from_canonical_bytes(buf).into(); + res.ok_or(anyhow::anyhow!( "Deserialization failed! Not a field value!" - ))?; - Ok(res.into()) - } -} - -impl Field for RistrettoScalar { - fn random(rng: &mut R) -> Self { - let mut scalar_bytes = [0u8; 64]; - rng.fill_bytes(&mut scalar_bytes); - Scalar::from_bytes_mod_order_wide(&scalar_bytes).into() - } - - fn zero() -> Self { Scalar::zero().into() } - - fn one() -> Self { Scalar::one().into() } - - fn is_zero(&self) -> bool { self.0 == Self::zero().0 } - - fn square(&mut self) { self.0.mul_assign(self.0) } - - fn double(&mut self) { self.0.add_assign(self.0) } - - fn negate(&mut self) { - let v = self.0.neg(); - self.0 = v; - } - - fn add_assign(&mut self, other: &Self) { self.0.add_assign(other.0) } - - fn sub_assign(&mut self, other: &Self) { self.0.sub_assign(other.0) } - - fn mul_assign(&mut self, other: &Self) { self.0.mul_assign(other.0) } - - fn inverse(&self) -> Option { - if self.is_zero() { - None - } else { - Some(self.0.invert().into()) - } + )) } } -impl PrimeField for RistrettoScalar { - // Taken from `curve25519-dalek` v.4.1.1 that implements `ff::PrimeField` - const CAPACITY: u32 = 252; - // Taken from `curve25519-dalek` v.4.1.1 that implements `ff::PrimeField`` - const NUM_BITS: u32 = 253; +impl PrimeField for FFField { + const CAPACITY: u32 = ::CAPACITY; + const NUM_BITS: u32 = ::NUM_BITS; fn into_repr(self) -> Vec { + let bytes = ::to_repr(&self.0); let mut vec: Vec = Vec::new(); - let bytes: [u8; 32] = self.0.to_bytes(); for chunk in bytes.chunks_exact(8) { // The chunk size is always 8 and there is no remainder after chunking, since // the representation is a 32-byte array. That is why it is safe to @@ -104,10 +58,12 @@ impl PrimeField for RistrettoScalar { LittleEndian::write_u64(&mut s_bytes[offset..max], x); offset = max; } - let res = Scalar::from_canonical_bytes(s_bytes).ok_or( - super::CurveDecodingError::NotInField(format!("{:?}", s_bytes)), - )?; - Ok(res.into()) + let res: Option<_> = Scalar::from_canonical_bytes(s_bytes).into(); + let scalar: Scalar = res.ok_or(super::CurveDecodingError::NotInField(format!( + "{:?}", + s_bytes + )))?; + Ok(scalar.into()) } } @@ -124,16 +80,15 @@ impl Deserial for RistrettoPoint { fn deserial(source: &mut R) -> crate::common::ParseResult { let mut buf: [u8; 32] = [0; 32]; source.read_exact(&mut buf)?; - let res = CompressedRistretto::from_slice(&buf) - .decompress() - .ok_or(anyhow::anyhow!("Failed!"))?; - Ok(res) + let res = CompressedRistretto::from_slice(&buf)?; + let point = res.decompress().ok_or(anyhow::anyhow!("Failed!"))?; + Ok(point) } } impl Curve for RistrettoPoint { type MultiExpType = RistrettoMultiExpNoPrecompute; - type Scalar = RistrettoScalar; + type Scalar = FFField; const GROUP_ELEMENT_LENGTH: usize = 32; const SCALAR_LENGTH: usize = 32; @@ -158,17 +113,6 @@ impl Curve for RistrettoPoint { fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self { self * scalar.0 } - fn bytes_to_curve_unchecked( - source: &mut R, - ) -> anyhow::Result { - let mut buf: [u8; 32] = [0; 32]; - source.read_exact(&mut buf)?; - let res = CompressedRistretto::from_slice(&buf) - .decompress() - .ok_or(anyhow::anyhow!("Failed!"))?; - Ok(res) - } - fn generate(rng: &mut R) -> Self { let mut uniform_bytes = [0u8; 64]; rng.fill_bytes(&mut uniform_bytes); @@ -191,12 +135,12 @@ impl Curve for RistrettoPoint { } // unset four topmost bits in the last u64 limb. fr[3] &= !(1u64 << 63 | 1u64 << 62 | 1u64 << 61 | 1u64 << 60); - ::from_repr(&fr) + ::from_repr(&fr) .expect("The scalar with top two bits erased should be valid.") } - fn hash_to_group(m: &[u8]) -> Self { - RistrettoPoint::hash_from_bytes::(m) + fn hash_to_group(m: &[u8]) -> Result { + Result::Ok(RistrettoPoint::hash_from_bytes::(m)) } } @@ -249,13 +193,17 @@ impl MultiExp for RistrettoMultiExpNoPrecompute { /// implementation, which features its own test suite. #[cfg(test)] pub(crate) mod tests { - use super::{RistrettoScalar, *}; - use crate::common::*; - use curve25519_dalek::ristretto::RistrettoPoint; - use rand::Rng; - use rand_core::RngCore; + use super::*; + use crate::{ + common::*, + curve_arithmetic::{field_adapters::FFField, Field}, + }; + use curve25519_dalek::{ristretto::RistrettoPoint, Scalar}; + use rand::{Rng, RngCore}; use std::io::Cursor; + type RistrettoScalar = FFField; + /// Test serialization for scalars #[test] fn test_scalar_serialization() { @@ -297,29 +245,16 @@ pub(crate) mod tests { } } - /// Turn curve points into representations and back again, and compare. - #[test] - fn test_point_byte_conversion_unchecked() { - let mut csprng = rand::thread_rng(); - for _ in 0..1000 { - let point = RistrettoPoint::generate(&mut csprng); - let bytes = to_bytes(&point); - let point_res = RistrettoPoint::bytes_to_curve_unchecked(&mut Cursor::new(&bytes)); - assert!(point_res.is_ok()); - assert_eq!(point, point_res.unwrap()); - } - } - /// Test that `into_repr()` correclty converts a scalar constructed from a /// byte array to an array of limbs with least significant digits first. #[test] fn test_into() { - let s: RistrettoScalar = Scalar::from_canonical_bytes([ + let res: Option = Scalar::from_canonical_bytes([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, ]) - .expect("Expected a valid scalar") .into(); + let s: RistrettoScalar = res.expect("Expected a valid scalar").into(); assert_eq!(s.into_repr(), [1u64, 0u64, u64::MAX - 1, 0u64]); } @@ -360,10 +295,10 @@ pub(crate) mod tests { // Next, we create a byte array that is filled with random lower bytes, the last // byte is in [0; 15], that is, of the form 0b0000XXXX (big-endian). fits_capacity_bytes[0..31].copy_from_slice(&lower_bytes); - let n = rng.gen_range(0, 16); + let n = rng.gen_range(0..16); fits_capacity_bytes[31] = n; let fits_capacity = ::scalar_from_bytes(fits_capacity_bytes); - let i = rng.gen_range(1, 16); + let i = rng.gen_range(1..16); // Now, we create a byte array from lower bytes with the last byte being number // that is guaranteed to exceed `RistrettoScalar::CAPACITY`. let mut bytes: [u8; 32] = [0u8; 32]; diff --git a/rust-src/concordium_base/src/curve_arithmetic/field_adapters.rs b/rust-src/concordium_base/src/curve_arithmetic/field_adapters.rs new file mode 100644 index 000000000..56d197fec --- /dev/null +++ b/rust-src/concordium_base/src/curve_arithmetic/field_adapters.rs @@ -0,0 +1,60 @@ +//! Wrapper types and blanket implementations serving as adapters from +//! the `ff` crate `Field`. The Ristretto representation from the +//! `curve25519-dalek` uses the `ff` traits for the fields involved. The crate +//! is relatively widely used, so it could be useful for integrating with other +//! elliptic curve implementations. +use ff; +use rand::RngCore; + +use crate::common::{Deserial, Serial}; + +use super::Field; + +/// A wrapper type for `ff` field types. +#[derive(derive_more::From, Clone, Copy, Debug, PartialEq, Eq)] +pub struct FFField(pub(crate) F); + +/// Serialization is implemented by delegating the functionality to the wrapped +/// type. +impl Serial for FFField { + fn serial(&self, out: &mut B) { self.0.serial(out) } +} + +/// Deserialization is implemented by delegating the functionality to the +/// wrapped type. +impl Deserial for FFField { + fn deserial(source: &mut R) -> crate::common::ParseResult { + let res = F::deserial(source)?; + Ok(res.into()) + } +} + +/// A blanket implementation of the `Field` trait using the functionality of +/// `ff::Field`. This gives an implementation of our `Field` trait for +/// `FFField` for any `F` that implements `ff::Field`. +impl Field for FFField { + fn random(rng: &mut R) -> Self { F::random(rng).into() } + + fn zero() -> Self { F::ZERO.into() } + + fn one() -> Self { F::ONE.into() } + + fn is_zero(&self) -> bool { self.0.is_zero_vartime() } + + fn square(&mut self) { self.0 = self.0.square() } + + fn double(&mut self) { self.0 = self.0.double() } + + fn negate(&mut self) { self.0 = self.0.neg() } + + fn add_assign(&mut self, other: &Self) { self.0.add_assign(other.0) } + + fn sub_assign(&mut self, other: &Self) { self.0.sub_assign(other.0) } + + fn mul_assign(&mut self, other: &Self) { self.0.mul_assign(other.0) } + + fn inverse(&self) -> Option { + let res: Option<_> = self.0.invert().into(); + res.map(|x: F| x.into()) + } +} diff --git a/rust-src/concordium_base/src/curve_arithmetic/mod.rs b/rust-src/concordium_base/src/curve_arithmetic/mod.rs index d70dd52d8..9320ddc13 100644 --- a/rust-src/concordium_base/src/curve_arithmetic/mod.rs +++ b/rust-src/concordium_base/src/curve_arithmetic/mod.rs @@ -1,15 +1,14 @@ //! Basic definitions of the curve and pairing abstractions, and implementations //! of these abstractions for the curves used on Concordium. -mod bls12_381_g1hash; -mod bls12_381_g2hash; -mod bls12_381_instance; +pub mod arkworks_instances; +mod bls12_381_arkworks; mod ed25519_instance; +mod field_adapters; pub mod secret_value; pub use secret_value::{Secret, Value}; use crate::common::{Serial, Serialize}; -use byteorder::ReadBytesExt; use rand::*; use std::{borrow::Borrow, fmt, fmt::Debug}; use thiserror::Error; @@ -88,7 +87,9 @@ pub trait PrimeField: Field { const NUM_BITS: u32; /// How many bits of information can be reliably stored in the field - /// element. + /// element. It is expected that `num_limbs * 64 - CAPACITY < 64`, where + /// `num_limbs` is the size of vector returned by + /// [PrimeField::into_repr]. const CAPACITY: u32; /// Get a big integer representation with least significant digit first. @@ -136,10 +137,6 @@ pub trait Curve: /// Exponentiation by a scalar, i.e., compute n * x for a group element x /// and integer n. fn mul_by_scalar(&self, scalar: &Self::Scalar) -> Self; - /// Deserialize a value from a byte source, but do not check that it is in - /// the group itself. This can be cheaper if the source of the value is - /// trusted, but it must not be used on untrusted sources. - fn bytes_to_curve_unchecked(b: &mut R) -> anyhow::Result; /// Generate a random group element, uniformly distributed. fn generate(rng: &mut R) -> Self; /// Generate a random scalar value, uniformly distributed. @@ -157,11 +154,15 @@ pub trait Curve: /// Make a scalar from a 64-bit unsigned integer. This function assumes that /// the field is big enough to accommodate any 64-bit unsigned integer. fn scalar_from_u64(n: u64) -> Self::Scalar; - /// Make a scalar by taking the first Scalar::CAPACITY bits and interpreting - /// them as a little-endian integer. + /// Make a scalar by taking the first `Scalar::CAPACITY`` bits and + /// interpreting them as a little-endian integer. If the input length is + /// smaller than `num_limbs * 8` bytes then extra zeros are added in topmost + /// bytes. If the input lenght is greater, bytes after the first + /// `num_limbs * 8` are ignored. Where `num_limbs` is the size of vector + /// returned by [PrimeField::into_repr]. fn scalar_from_bytes>(bs: A) -> Self::Scalar; /// Hash to a curve point from a seed. This is deterministic function. - fn hash_to_group(m: &[u8]) -> Self; + fn hash_to_group(m: &[u8]) -> Result; } /// An abstraction over a multiexp algorithm. @@ -416,8 +417,10 @@ where #[cfg(test)] mod tests { - use super::*; - use pairing::bls12_381::G1; + use super::{arkworks_instances::ArkGroup, *}; + use ark_bls12_381::G1Projective; + + type SomeCurve = ArkGroup; #[test] pub fn test_multiscalar() { @@ -426,10 +429,10 @@ mod tests { let mut gs = Vec::with_capacity(l); let mut es = Vec::with_capacity(l); for _ in 0..l { - gs.push(G1::generate(&mut csprng)); - es.push(G1::generate_scalar(&mut csprng)); + gs.push(SomeCurve::generate(&mut csprng)); + es.push(SomeCurve::generate_scalar(&mut csprng)); } - let mut goal = G1::zero_point(); + let mut goal = SomeCurve::zero_point(); // Naive multiply + add method. for (g, e) in gs.iter().zip(es.iter()) { goal = goal.plus_point(&g.mul_by_scalar(e)) diff --git a/rust-src/concordium_base/src/curve_arithmetic/secret_value.rs b/rust-src/concordium_base/src/curve_arithmetic/secret_value.rs index 60d38b1f5..ad3d40be5 100644 --- a/rust-src/concordium_base/src/curve_arithmetic/secret_value.rs +++ b/rust-src/concordium_base/src/curve_arithmetic/secret_value.rs @@ -99,8 +99,11 @@ impl Value { #[cfg(test)] mod tests { + use ark_bls12_381::{G1Projective, G2Projective}; + + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1Affine, G2Affine}; macro_rules! macro_test_value_to_byte_conversion { ($function_name:ident, $curve_type:path) => { #[test] @@ -117,7 +120,13 @@ mod tests { }; } - macro_test_value_to_byte_conversion!(value_to_byte_conversion_bls12_381_g1_affine, G1Affine); + macro_test_value_to_byte_conversion!( + value_to_byte_conversion_bls12_381_g1_projective, + ArkGroup + ); - macro_test_value_to_byte_conversion!(value_to_byte_conversion_bls12_381_g2_affine, G2Affine); + macro_test_value_to_byte_conversion!( + value_to_byte_conversion_bls12_381_g2_projective, + ArkGroup + ); } diff --git a/rust-src/concordium_base/src/dodis_yampolskiy_prf/secret.rs b/rust-src/concordium_base/src/dodis_yampolskiy_prf/secret.rs index 662963f5f..acfb374be 100644 --- a/rust-src/concordium_base/src/dodis_yampolskiy_prf/secret.rs +++ b/rust-src/concordium_base/src/dodis_yampolskiy_prf/secret.rs @@ -106,12 +106,16 @@ impl std::str::FromStr for SecretKey { #[cfg(test)] mod tests { use super::*; - use pairing::bls12_381::G1; + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use ark_bls12_381::G1Projective; + + type SomeCurve = ArkGroup; + #[test] pub fn key_to_byte_conversion() { let mut csprng = thread_rng(); for _ in 1..100 { - let sk = SecretKey::::generate(&mut csprng); + let sk = SecretKey::::generate(&mut csprng); let res_sk2 = serialize_deserialize(&sk); assert!(res_sk2.is_ok()); let sk2 = res_sk2.unwrap(); diff --git a/rust-src/concordium_base/src/ecvrf/mod.rs b/rust-src/concordium_base/src/ecvrf/mod.rs index 2da0fae6f..c365b3518 100644 --- a/rust-src/concordium_base/src/ecvrf/mod.rs +++ b/rust-src/concordium_base/src/ecvrf/mod.rs @@ -262,7 +262,7 @@ mod tests { // Test serialization of generated secret scalar let x = expanded_sk.key; - assert_eq!(x, Scalar::from_bits(x_bytes)); + assert_eq!(x, Scalar::from_bytes_mod_order(x_bytes)); // Test serialization of proof let proof = expanded_sk.prove(&pk, &alpha_bytes); diff --git a/rust-src/concordium_base/src/ecvrf/proof.rs b/rust-src/concordium_base/src/ecvrf/proof.rs index bc2fa18cd..fc63bc41a 100644 --- a/rust-src/concordium_base/src/ecvrf/proof.rs +++ b/rust-src/concordium_base/src/ecvrf/proof.rs @@ -29,24 +29,26 @@ pub fn hash_points(pts: &[CompressedEdwardsY]) -> Scalar { /// a given public key. pub struct Proof(pub EdwardsPoint, pub Scalar, pub Scalar); -/// Implements step 8 of +/// Implements step 8 of /// i.e. transforms a proof to a byte string impl Serial for Proof { #[inline] fn serial(&self, x: &mut B) { - let c = &self.1.reduce().to_bytes(); + // The scalar is already reduced https://docs.rs/curve25519-dalek/4.1.1/src/curve25519_dalek/scalar.rs.html#211, + // so we just convert it to bytes. + let c = &self.1.to_bytes(); // assert c is within range assert_eq!(c[16..32], [0u8; 16]); x.write_all(&self.0.compress().to_bytes()[..]) .expect("Writing to buffer should succeed."); x.write_all(&c[..16]) .expect("Writing to buffer should succeed."); - x.write_all(&self.2.reduce().to_bytes()[..]) + x.write_all(&self.2.to_bytes()[..]) .expect("Writing to buffer should succeed."); } } -/// Implements +/// Implements /// Construct a `Proof` from a slice of bytes. This function always /// results in a valid proof object. impl Deserial for Proof { @@ -61,9 +63,9 @@ impl Deserial for Proof { let compressed_point = CompressedEdwardsY(point_bytes); match compressed_point.decompress() { None => Err(ProofError(InternalError::PointDecompression).into()), - Some(p) => match Scalar::from_canonical_bytes(scalar_bytes1) { + Some(p) => match Scalar::from_canonical_bytes(scalar_bytes1).into() { None => Err(ProofError(InternalError::ScalarFormat).into()), - Some(s1) => match Scalar::from_canonical_bytes(scalar_bytes2) { + Some(s1) => match Scalar::from_canonical_bytes(scalar_bytes2).into() { None => Err(ProofError(InternalError::ScalarFormat).into()), Some(s2) => Ok(Proof(p, s1, s2)), }, @@ -78,7 +80,7 @@ impl Debug for Proof { } } -/// Implements +/// Implements impl Proof { pub fn to_hash(&self) -> [u8; 64] { let p = self.0.mul_by_cofactor(); diff --git a/rust-src/concordium_base/src/ecvrf/public.rs b/rust-src/concordium_base/src/ecvrf/public.rs index bbb84a62d..56e36c4c0 100644 --- a/rust-src/concordium_base/src/ecvrf/public.rs +++ b/rust-src/concordium_base/src/ecvrf/public.rs @@ -5,7 +5,6 @@ use core::fmt::Debug; use curve25519_dalek::{ constants, edwards::{CompressedEdwardsY, EdwardsPoint}, - scalar::Scalar, }; use sha2::{Digest, Sha512}; @@ -61,25 +60,20 @@ impl From<&SecretKey> for PublicKey { /// Derive this public key from its corresponding `SecretKey`. /// Implements fn from(secret_key: &SecretKey) -> PublicKey { - let mut h: Sha512 = Sha512::new(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut digest: [u8; 32] = [0u8; 32]; - - h.update(secret_key.as_bytes()); - hash.copy_from_slice(h.finalize().as_slice()); - - digest.copy_from_slice(&hash[..32]); - - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) + let expanded = ExpandedSecretKey::from(secret_key); + (&expanded).into() } } impl From<&ExpandedSecretKey> for PublicKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { - let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); + let key = expanded_secret_key.key; + + let point = &key * constants::ED25519_BASEPOINT_TABLE; + let compressed = point.compress(); - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) + PublicKey(compressed, point) } } @@ -88,23 +82,7 @@ impl PublicKey { #[inline] pub fn as_bytes(&self) -> &'_ [u8; PUBLIC_KEY_LENGTH] { &(self.0).0 } - /// Internal utility function for mangling the bits of a (formerly - /// mathematically well-defined) "scalar" and multiplying it to produce a - /// public key. - fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( - bits: &mut [u8; 32], - ) -> PublicKey { - bits[0] &= 0b_1111_1000; - bits[31] &= 0b_0111_1111; - bits[31] |= 0b_0100_0000; - - let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; - let compressed = point.compress(); - - PublicKey(compressed, point) - } - - /// Implements + /// Implements /// The failure should not happen in practice, expected number of iterations /// is 2. pub fn hash_to_curve(&self, message: &[u8]) -> Option { @@ -115,7 +93,7 @@ impl PublicKey { h.update(self.as_bytes()); // PK_string h.update(message); // alpha_string for ctr in 0..=u8::max_value() { - // Each iteration fails, indpendent of other iterations, with probability about + // Each iteration fails, independent of other iterations, with probability about // a half. This happens if the digest does not represent a point on // the curve when decoded as in https://tools.ietf.org/html/rfc8032#section-5.1.3 let mut attempt_h = h.clone(); @@ -137,7 +115,7 @@ impl PublicKey { pub fn verify_key(&self) -> bool { !self.1.is_small_order() } - /// Implements + /// Implements #[allow(clippy::many_single_char_names)] pub fn verify(&self, pi: &Proof, message: &[u8]) -> bool { if let Some(h) = self.hash_to_curve(message) { @@ -145,7 +123,7 @@ impl PublicKey { // generated nonce and x is the secret key // self should be equal y=b^x - let b_to_s = s * &constants::ED25519_BASEPOINT_TABLE; // should be equal to b^(k+cx) + let b_to_s = s * constants::ED25519_BASEPOINT_TABLE; // should be equal to b^(k+cx) let y_to_c = c * self.1; // y_to_c should be equal to b^(cx) let u = b_to_s - y_to_c; // should equal b^k diff --git a/rust-src/concordium_base/src/ecvrf/secret.rs b/rust-src/concordium_base/src/ecvrf/secret.rs index 633e78912..77469b883 100644 --- a/rust-src/concordium_base/src/ecvrf/secret.rs +++ b/rust-src/concordium_base/src/ecvrf/secret.rs @@ -3,7 +3,10 @@ use super::{constants::*, errors::*, public::*}; use crate::common::*; use core::fmt::Debug; -use curve25519_dalek::{constants, scalar::Scalar}; +use curve25519_dalek::{ + constants, + scalar::{clamp_integer, Scalar}, +}; use rand::{CryptoRng, Rng}; use sha2::{digest::Digest, Sha512}; use subtle::{Choice, ConstantTimeEq}; @@ -123,12 +126,8 @@ impl From<&SecretKey> for ExpandedSecretKey { lower.copy_from_slice(&hash[00..32]); upper.copy_from_slice(&hash[32..64]); - lower[0] &= 0b_1111_1000; - lower[31] &= 0b_0111_1111; - lower[31] |= 0b_0100_0000; - ExpandedSecretKey { - key: Scalar::from_bits(lower), + key: Scalar::from_bytes_mod_order(clamp_integer(lower)), nonce: upper, } } @@ -137,7 +136,7 @@ use super::proof::*; impl ExpandedSecretKey { /// VRF proof with expanded secret key - /// Implements + /// Implements pub fn prove(&self, public_key: &PublicKey, alpha: &[u8]) -> Proof { let x = self.key; let h = public_key @@ -160,7 +159,7 @@ impl ExpandedSecretKey { Proof(gamma, c, k_plus_cx) } - /// Implements + /// Implements fn nonce_generation(&self, h_string: &[u8]) -> Scalar { let digest = Sha512::new() .chain_update(self.nonce) diff --git a/rust-src/concordium_base/src/eddsa_ed25519/dlog_ed25519.rs b/rust-src/concordium_base/src/eddsa_ed25519/dlog_ed25519.rs index 3e5753f6a..290c30f48 100644 --- a/rust-src/concordium_base/src/eddsa_ed25519/dlog_ed25519.rs +++ b/rust-src/concordium_base/src/eddsa_ed25519/dlog_ed25519.rs @@ -33,9 +33,9 @@ impl Deserial for Ed25519DlogProof { fn deserial(source: &mut R) -> ParseResult { let mut buf = [0; 32]; source.read_exact(&mut buf)?; - if let Some(challenge) = Scalar::from_canonical_bytes(buf) { + if let Some(challenge) = Scalar::from_canonical_bytes(buf).into() { source.read_exact(&mut buf)?; - if let Some(response) = Scalar::from_canonical_bytes(buf) { + if let Some(response) = Scalar::from_canonical_bytes(buf).into() { Ok(Ed25519DlogProof { challenge, response, @@ -61,20 +61,20 @@ pub enum PointDecodingError { fn scalar_from_secret_key(secret_key: &impl AsRef<[u8]>) -> Scalar { let mut h = Sha512::new(); + // inspired by this https://docs.rs/ed25519-dalek/2.1.0/src/ed25519_dalek/hazmat.rs.html#61-76 let mut hash: [u8; 64] = [0u8; 64]; - let mut bits: [u8; 32] = [0u8; 32]; + let mut scalar_bytes: [u8; 32] = [0u8; 32]; h.update(secret_key); hash.copy_from_slice(h.finalize().as_slice()); - bits.copy_from_slice(&hash[..32]); - bits[0] &= 248; - bits[31] &= 127; - bits[31] |= 64; - Scalar::from_bits(bits) + scalar_bytes.copy_from_slice(&hash[..32]); + + Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes)) } -fn point_from_public_key(public_key: &PublicKey) -> Option { +fn point_from_public_key(public_key: &VerifyingKey) -> Option { let bytes = public_key.to_bytes(); - CompressedEdwardsY::from_slice(&bytes).decompress() + let res = CompressedEdwardsY::from_slice(&bytes).ok()?; + res.decompress() } /// Construct a proof of knowledge of secret key. @@ -99,7 +99,7 @@ pub fn prove_dlog_ed25519( let rand_scalar = Scalar::random(csprng); - let randomised_point = &rand_scalar * &constants::ED25519_BASEPOINT_TABLE; + let randomised_point = &rand_scalar * constants::ED25519_BASEPOINT_TABLE; ro.append_message(b"randomised_point", &randomised_point.compress().to_bytes()); let challenge_bytes = ro.split().result(); @@ -115,14 +115,14 @@ pub fn prove_dlog_ed25519( pub fn verify_dlog_ed25519( ro: &mut RandomOracle, - public_key: &PublicKey, + public_key: &VerifyingKey, proof: &Ed25519DlogProof, ) -> bool { match point_from_public_key(public_key) { None => false, Some(public) => { let randomised_point = - public * proof.challenge + &proof.response * &constants::ED25519_BASEPOINT_TABLE; + public * proof.challenge + &proof.response * constants::ED25519_BASEPOINT_TABLE; ro.append_message(b"dlog_ed25519", public_key); ro.append_message(b"randomised_point", &randomised_point.compress().to_bytes()); @@ -143,7 +143,7 @@ mod tests { fn generate_challenge_prefix(csprng: &mut R) -> Vec { // length of the challenge - let l = csprng.gen_range(0, 1000); + let l = csprng.gen_range(0..1000); let mut challenge_prefix = vec![0; l]; for v in challenge_prefix.iter_mut() { *v = csprng.gen(); @@ -155,8 +155,9 @@ mod tests { pub fn test_ed25519_dlog() { let mut csprng = thread_rng(); for _ in 0..10000 { - let secret = SecretKey::generate(&mut csprng); - let public = PublicKey::from(&secret); + let signing = SigningKey::generate(&mut csprng); + let secret = signing.to_bytes(); + let public = signing.verifying_key(); let challenge_prefix = generate_challenge_prefix(&mut csprng); let mut ro = RandomOracle::domain(&challenge_prefix); let proof = prove_dlog_ed25519(&mut csprng, &mut ro.split(), &public, &secret); @@ -176,8 +177,10 @@ mod tests { pub fn test_ed25519_dlog_proof_serialization() { let mut csprng = thread_rng(); for _ in 0..10000 { - let secret = SecretKey::generate(&mut csprng); - let public = PublicKey::from(&secret); + let signing = SigningKey::generate(&mut csprng); + let secret = signing.to_bytes(); + let signing = SigningKey::from_bytes(&secret); + let public = signing.verifying_key(); let challenge_prefix = generate_challenge_prefix(&mut csprng); let proof = prove_dlog_ed25519( &mut csprng, diff --git a/rust-src/concordium_base/src/eddsa_ed25519/ffi.rs b/rust-src/concordium_base/src/eddsa_ed25519/ffi.rs index f4e956f00..d1483addd 100644 --- a/rust-src/concordium_base/src/eddsa_ed25519/ffi.rs +++ b/rust-src/concordium_base/src/eddsa_ed25519/ffi.rs @@ -12,27 +12,29 @@ use crate::random_oracle::RandomOracle; #[no_mangle] extern "C" fn eddsa_priv_key() -> *mut SecretKey { let mut csprng = thread_rng(); - let sk = SecretKey::generate(&mut csprng); - Box::into_raw(Box::new(sk)) + let mut secret_key = SecretKey::default(); + csprng.fill_bytes(&mut secret_key); + Box::into_raw(Box::new(secret_key)) } -// error encodeing +// error encoding //-1 bad input #[no_mangle] #[allow(clippy::not_unsafe_ptr_arg_deref)] -extern "C" fn eddsa_pub_key(sk_ptr: *mut SecretKey) -> *mut PublicKey { - let sk = from_ptr!(sk_ptr); - Box::into_raw(Box::new(PublicKey::from(sk))) +extern "C" fn eddsa_pub_key(sk_ptr: *mut SecretKey) -> *mut VerifyingKey { + let secret_key = from_ptr!(sk_ptr); + let signing_key = SigningKey::from_bytes(secret_key); + Box::into_raw(Box::new(signing_key.verifying_key())) } macro_free_ffi!(Box eddsa_sign_free, SecretKey); -macro_free_ffi!(Box eddsa_public_free, PublicKey); +macro_free_ffi!(Box eddsa_public_free, VerifyingKey); #[no_mangle] #[allow(clippy::not_unsafe_ptr_arg_deref)] extern "C" fn eddsa_sign_to_bytes(input_ptr: *mut SecretKey, output_len: *mut size_t) -> *const u8 { let input = from_ptr!(input_ptr); - let bytes = input.to_bytes().to_vec(); + let bytes = input.to_vec(); unsafe { *output_len = bytes.len() as size_t } let ret_ptr = bytes.as_ptr(); ::std::mem::forget(bytes); @@ -42,7 +44,7 @@ extern "C" fn eddsa_sign_to_bytes(input_ptr: *mut SecretKey, output_len: *mut si #[no_mangle] #[allow(clippy::not_unsafe_ptr_arg_deref)] extern "C" fn eddsa_public_to_bytes( - input_ptr: *mut PublicKey, + input_ptr: *mut VerifyingKey, output_len: *mut size_t, ) -> *const u8 { let input = from_ptr!(input_ptr); @@ -55,13 +57,21 @@ extern "C" fn eddsa_public_to_bytes( #[no_mangle] #[allow(clippy::not_unsafe_ptr_arg_deref)] -extern "C" fn eddsa_public_from_bytes(input_bytes: *mut u8, input_len: size_t) -> *mut PublicKey { +extern "C" fn eddsa_public_from_bytes( + input_bytes: *mut u8, + input_len: size_t, +) -> *mut VerifyingKey { let len = input_len; let bytes = slice_from_c_bytes!(input_bytes, len); - let e = PublicKey::from_bytes(bytes); - match e { - Ok(r) => Box::into_raw(Box::new(r)), - Err(_) => ::std::ptr::null_mut(), + let res: Result<[u8; 32], _> = bytes.try_into(); + if let Ok(byte_array) = res { + let e = VerifyingKey::from_bytes(&byte_array); + match e { + Ok(r) => Box::into_raw(Box::new(r)), + Err(_) => ::std::ptr::null_mut(), + } + } else { + ::std::ptr::null_mut() } } @@ -70,8 +80,8 @@ extern "C" fn eddsa_public_from_bytes(input_bytes: *mut u8, input_len: size_t) - extern "C" fn eddsa_sign_from_bytes(input_bytes: *mut u8, input_len: size_t) -> *mut SecretKey { let len = input_len; let bytes = slice_from_c_bytes!(input_bytes, len); - let e = SecretKey::from_bytes(bytes); - match e { + let res: Result<[u8; 32], _> = bytes.try_into(); + match res { Ok(r) => Box::into_raw(Box::new(r)), Err(_) => ::std::ptr::null_mut(), } @@ -83,14 +93,12 @@ extern "C" fn eddsa_sign( message: *const u8, len: usize, sk_ptr: *mut SecretKey, - pk_ptr: *mut PublicKey, signature_bytes: &mut [u8; SIGNATURE_LENGTH], ) { let sk = from_ptr!(sk_ptr); - let pk = from_ptr!(pk_ptr); let data: &[u8] = slice_from_c_bytes!(message, len); - let expanded_sk = ExpandedSecretKey::from(sk); - let signature = expanded_sk.sign(data, pk); + let expanded_sk = SigningKey::from(sk); + let signature = expanded_sk.sign(data); signature_bytes.copy_from_slice(&signature.to_bytes()); } // Error encoding @@ -101,7 +109,7 @@ extern "C" fn eddsa_sign( extern "C" fn eddsa_verify( message: *const u8, len: usize, - pk_ptr: *mut PublicKey, + pk_ptr: *mut VerifyingKey, signature_bytes: &[u8; SIGNATURE_LENGTH], ) -> i32 { let sig = match Signature::try_from(&signature_bytes[..]) { @@ -127,9 +135,14 @@ extern "C" fn eddsa_verify_dlog_ed25519( let challenge = slice_from_c_bytes!(challenge_prefix_ptr, challenge_len); let public_key = { let pk_bytes = slice_from_c_bytes!(public_key_bytes, PUBLIC_KEY_LENGTH); - match PublicKey::from_bytes(pk_bytes) { - Err(_) => return -1, - Ok(pk) => pk, + let res: Result<[u8; 32], _> = pk_bytes.try_into(); + if let Ok(pk_byte_array) = res { + match VerifyingKey::from_bytes(&pk_byte_array) { + Err(_) => return -1, + Ok(pk) => pk, + } + } else { + return -1; } }; let proof = { @@ -158,16 +171,23 @@ extern "C" fn eddsa_prove_dlog_ed25519( let challenge = slice_from_c_bytes!(challenge_prefix_ptr, challenge_len); let public_key = { let pk_bytes = slice_from_c_bytes!(public_key_bytes, PUBLIC_KEY_LENGTH); - match PublicKey::from_bytes(pk_bytes) { - Err(_) => return -1, - Ok(pk) => pk, + let res: Result<[u8; PUBLIC_KEY_LENGTH], _> = pk_bytes.try_into(); + if let Ok(pk_byte_array) = res { + match VerifyingKey::from_bytes(&pk_byte_array) { + Err(_) => return -1, + Ok(pk) => pk, + } + } else { + return -1; } }; let secret_key = { let sk_bytes = slice_from_c_bytes!(secret_key_bytes, SECRET_KEY_LENGTH); - match SecretKey::from_bytes(sk_bytes) { - Err(_) => return -2, - Ok(sk) => sk, + let res: Result<[u8; 32], _> = sk_bytes.try_into(); + if let Ok(sk_byte_array) = res { + sk_byte_array + } else { + return -2; } }; let proof_bytes = mut_slice_from_c_bytes!(proof_ptr, PROOF_LENGTH); diff --git a/rust-src/concordium_base/src/elgamal/cipher.rs b/rust-src/concordium_base/src/elgamal/cipher.rs index 514a60725..388fb5104 100644 --- a/rust-src/concordium_base/src/elgamal/cipher.rs +++ b/rust-src/concordium_base/src/elgamal/cipher.rs @@ -56,9 +56,9 @@ impl Cipher { /// A `Result` whose okay value is a cipher key or whose error value /// is an `ElgamalError` wrapping the internal error that occurred. #[inline] - pub fn from_bytes_unchecked(bytes: &mut R) -> anyhow::Result> { - let g = C::bytes_to_curve_unchecked(bytes)?; - let h = C::bytes_to_curve_unchecked(bytes)?; + pub fn from_bytes(bytes: &mut R) -> anyhow::Result> { + let g = C::deserial(bytes)?; + let h = C::deserial(bytes)?; Ok(Cipher(g, h)) } @@ -109,8 +109,10 @@ pub fn multicombine(ciphers: &[Cipher], scalars: &[C::Scalar]) -> C #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1, G2}; + use ark_bls12_381::{G1Projective, G2Projective}; macro_rules! macro_test_cipher_to_byte_conversion { ($function_name:ident, $curve_type:path) => { @@ -127,6 +129,6 @@ mod tests { }; } - macro_test_cipher_to_byte_conversion!(key_to_cipher_conversion_g1, G1); - macro_test_cipher_to_byte_conversion!(key_to_cipher_conversion_g2, G2); + macro_test_cipher_to_byte_conversion!(key_to_cipher_conversion_g1, ArkGroup); + macro_test_cipher_to_byte_conversion!(key_to_cipher_conversion_g2, ArkGroup); } diff --git a/rust-src/concordium_base/src/elgamal/message.rs b/rust-src/concordium_base/src/elgamal/message.rs index 30cc7e2bd..ec0f29eea 100644 --- a/rust-src/concordium_base/src/elgamal/message.rs +++ b/rust-src/concordium_base/src/elgamal/message.rs @@ -25,8 +25,11 @@ impl Message { #[cfg(test)] mod tests { + use ark_bls12_381::{G1Projective, G2Projective}; + + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1, G2}; fn test_message_serialization_helper() { let mut csprng = thread_rng(); @@ -39,7 +42,11 @@ mod tests { } #[test] - pub fn message_to_byte_conversion_g1() { test_message_serialization_helper::(); } + pub fn message_to_byte_conversion_g1() { + test_message_serialization_helper::>(); + } #[test] - pub fn message_to_byte_conversion_g2() { test_message_serialization_helper::(); } + pub fn message_to_byte_conversion_g2() { + test_message_serialization_helper::>(); + } } diff --git a/rust-src/concordium_base/src/elgamal/mod.rs b/rust-src/concordium_base/src/elgamal/mod.rs index 965943f04..2451ba01a 100644 --- a/rust-src/concordium_base/src/elgamal/mod.rs +++ b/rust-src/concordium_base/src/elgamal/mod.rs @@ -207,8 +207,10 @@ pub fn decrypt_from_chunks_given_table( #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1, G2}; + use ark_bls12_381::{G1Projective, G2Projective}; use rand::{rngs::ThreadRng, Rng}; // This is a generic helper function that tests encryption/decryption in chunks. @@ -231,10 +233,14 @@ mod tests { } #[test] - fn encrypt_decrypt_success_g1() { test_encrypt_decrypt_success_generic::() } + fn encrypt_decrypt_success_g1() { + test_encrypt_decrypt_success_generic::>() + } #[test] - fn encrypt_decrypt_success_g2() { test_encrypt_decrypt_success_generic::() } + fn encrypt_decrypt_success_g2() { + test_encrypt_decrypt_success_generic::>() + } // This is a generic helper function that tests encryption/decryption in chunks. // It is parameterized by a curve, and the intention is that concrete tests are @@ -244,7 +250,7 @@ mod tests { let sk: SecretKey = SecretKey::generate_all(&mut csprng); let pk = PublicKey::from(&sk); for _i in 1..10 { - let n = csprng.gen_range(0, 1000); + let n = csprng.gen_range(0..1000); let mut e = ::Scalar::zero(); let one_scalar = Value::::new(::Scalar::one()); for _ in 0..n { @@ -259,12 +265,12 @@ mod tests { #[test] fn encrypt_decrypt_exponent_success_g1() { - test_encrypt_decrypt_exponent_success_generic::() + test_encrypt_decrypt_exponent_success_generic::>() } #[test] fn encrypt_decrypt_exponent_success_g2() { - test_encrypt_decrypt_exponent_success_generic::() + test_encrypt_decrypt_exponent_success_generic::>() } // This is a generic helper function that tests encryption/decryption in chunks. @@ -278,7 +284,7 @@ mod tests { for _i in 1..10 { let scalar = Value::::generate(&mut csprng); - let chunk_size_index: usize = csprng.gen_range(0, possible_chunk_sizes.len()); + let chunk_size_index: usize = csprng.gen_range(0..possible_chunk_sizes.len()); let chunk_size = possible_chunk_sizes[chunk_size_index]; let chunks = value_to_chunks::(&scalar, chunk_size); let retrieved_scalar = chunks_to_value::(&chunks, chunk_size); @@ -288,7 +294,7 @@ mod tests { } #[test] - fn chunking_test_g1() { test_chunking_generic::() } + fn chunking_test_g1() { test_chunking_generic::>() } // This is a generic helper function that tests encryption/decryption in chunks. // It is parameterized by a curve, and the intention is that concrete tests are @@ -302,7 +308,7 @@ mod tests { for _i in 1..2 { let scalar = Value::::generate(&mut csprng); - let chunk_size_index: usize = csprng.gen_range(0, possible_chunk_sizes.len()); + let chunk_size_index: usize = csprng.gen_range(0..possible_chunk_sizes.len()); let chunk_size = possible_chunk_sizes[chunk_size_index]; let m = 1 << (u8::from(chunk_size) - 1); let cipher_pairs = @@ -317,5 +323,7 @@ mod tests { } #[test] - fn chunked_encrypt_decrypt_test_g1() { test_chunked_encrypt_decrypt_generic::() } + fn chunked_encrypt_decrypt_test_g1() { + test_chunked_encrypt_decrypt_generic::>() + } } diff --git a/rust-src/concordium_base/src/elgamal/public.rs b/rust-src/concordium_base/src/elgamal/public.rs index fe0e19514..7b5cf6e82 100644 --- a/rust-src/concordium_base/src/elgamal/public.rs +++ b/rust-src/concordium_base/src/elgamal/public.rs @@ -147,8 +147,11 @@ impl PublicKey { #[cfg(test)] mod tests { + use ark_bls12_381::{G1Projective, G2Projective}; + + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1, G2}; macro_rules! macro_test_key_to_byte_conversion { ($function_name:ident, $curve_type:path) => { @@ -167,6 +170,6 @@ mod tests { }; } - macro_test_key_to_byte_conversion!(key_to_byte_conversion_g1, G1); - macro_test_key_to_byte_conversion!(key_to_byte_conversion_g2, G2); + macro_test_key_to_byte_conversion!(key_to_byte_conversion_g1, ArkGroup); + macro_test_key_to_byte_conversion!(key_to_byte_conversion_g2, ArkGroup); } diff --git a/rust-src/concordium_base/src/elgamal/secret.rs b/rust-src/concordium_base/src/elgamal/secret.rs index edb1c2ad2..fd4b1f4e8 100644 --- a/rust-src/concordium_base/src/elgamal/secret.rs +++ b/rust-src/concordium_base/src/elgamal/secret.rs @@ -167,8 +167,12 @@ impl SecretKey { #[cfg(test)] mod tests { + use ark_bls12_381::{G1Projective, G2Projective}; + + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1, G2}; + macro_rules! macro_test_secret_key_to_byte_conversion { ($function_name:ident, $curve_type:path) => { #[test] @@ -185,8 +189,14 @@ mod tests { }; } - macro_test_secret_key_to_byte_conversion!(secret_key_to_byte_conversion_g1, G1); - macro_test_secret_key_to_byte_conversion!(secret_key_to_byte_conversion_g2, G2); + macro_test_secret_key_to_byte_conversion!( + secret_key_to_byte_conversion_g1, + ArkGroup + ); + macro_test_secret_key_to_byte_conversion!( + secret_key_to_byte_conversion_g2, + ArkGroup + ); // Test serialiation of baby-step-giant-step since it is implemented manually. #[test] @@ -194,7 +204,10 @@ mod tests { let mut csprng = thread_rng(); let m = 1 << 16; for _ in 0..10 { - let bsgs = BabyStepGiantStep::::new(&G1::generate(&mut csprng), m); + let bsgs = BabyStepGiantStep::>::new( + &>::generate(&mut csprng), + m, + ); let res = serialize_deserialize(&bsgs); assert!( res.is_ok(), diff --git a/rust-src/concordium_base/src/encrypted_transfers/ffi.rs b/rust-src/concordium_base/src/encrypted_transfers/ffi.rs index 9570ed1fe..bf22c9b28 100644 --- a/rust-src/concordium_base/src/encrypted_transfers/ffi.rs +++ b/rust-src/concordium_base/src/encrypted_transfers/ffi.rs @@ -3,11 +3,12 @@ //! scheduler, and the mobile wallet. use super::*; -use crate::{common::*, elgamal, ffi_helpers::*}; +use crate::{common::*, curve_arithmetic::arkworks_instances::ArkGroup, elgamal, ffi_helpers::*}; +use ark_bls12_381::G1Projective; use rand::prelude::StdRng; use std::io::Cursor; -type Group = pairing::bls12_381::G1; +type Group = ArkGroup; /// # Safety /// This function is safe if the pointers are all non-null, and produced diff --git a/rust-src/concordium_base/src/encrypted_transfers/mod.rs b/rust-src/concordium_base/src/encrypted_transfers/mod.rs index fc1f82eb1..6caf4a545 100644 --- a/rust-src/concordium_base/src/encrypted_transfers/mod.rs +++ b/rust-src/concordium_base/src/encrypted_transfers/mod.rs @@ -279,14 +279,18 @@ pub fn verify_sec_to_pub_transfer_data( #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; + + type SomeCurve = ArkGroup; // Test that decryption is the inverse to encryption. #[test] fn test_encrypt_decrypt() { let mut csprng = thread_rng(); - let context = GlobalContext::::generate(String::from("genesis_string")); + let context = GlobalContext::::generate(String::from("genesis_string")); let sk = SecretKey::generate(context.elgamal_generator(), &mut csprng); let pk = PublicKey::from(&sk); @@ -308,7 +312,7 @@ mod tests { #[test] fn test_scale() { let mut csprng = thread_rng(); - let context = GlobalContext::::generate(String::from("genesis_string")); + let context = GlobalContext::::generate(String::from("genesis_string")); let sk = SecretKey::generate(context.elgamal_generator(), &mut csprng); let pk = PublicKey::from(&sk); @@ -334,7 +338,7 @@ mod tests { #[test] fn test_encryption_randomness_zero() { let mut csprng = thread_rng(); - let context = GlobalContext::::generate(String::from("genesis_string")); + let context = GlobalContext::::generate(String::from("genesis_string")); let sk = SecretKey::generate(context.elgamal_generator(), &mut csprng); let amount = Amount::from_micro_ccd(csprng.gen::()); let dummy_encryption = encrypt_amount_with_fixed_randomness(&context, amount); @@ -352,19 +356,20 @@ mod tests { #[test] fn test_make_and_verify_transfer_data() { let mut csprng = thread_rng(); - let sk_sender: SecretKey = SecretKey::generate_all(&mut csprng); + let sk_sender: SecretKey = SecretKey::generate_all(&mut csprng); let pk_sender = PublicKey::from(&sk_sender); - let sk_receiver: SecretKey = SecretKey::generate(&pk_sender.generator, &mut csprng); + let sk_receiver: SecretKey = + SecretKey::generate(&pk_sender.generator, &mut csprng); let pk_receiver = PublicKey::from(&sk_receiver); let s: u64 = csprng.gen(); // amount on account. - let a = csprng.gen_range(0, s); // amount to send + let a = csprng.gen_range(0..s); // amount to send let m = 2; // 2 chunks let n = 32; let nm = n * m; - let context = GlobalContext::::generate_size(String::from("genesis_string"), nm); + let context = GlobalContext::::generate_size(String::from("genesis_string"), nm); let S_in_chunks = encrypt_amount(&context, &pk_sender, Amount::from_micro_ccd(s), &mut csprng); @@ -400,17 +405,17 @@ mod tests { #[allow(non_snake_case)] fn test_make_and_verify_sec_to_pub_transfer_data() { let mut csprng = thread_rng(); - let sk_sender: SecretKey = SecretKey::generate_all(&mut csprng); + let sk_sender: SecretKey = SecretKey::generate_all(&mut csprng); let pk_sender = PublicKey::from(&sk_sender); let s: u64 = csprng.gen(); // amount on account. - let a = csprng.gen_range(0, s); // amount to send + let a = csprng.gen_range(0..s); // amount to send let m = 2; // 2 chunks let n = 32; let nm = n * m; - let context = GlobalContext::::generate_size(String::from("genesis_string"), nm); + let context = GlobalContext::::generate_size(String::from("genesis_string"), nm); let S_in_chunks = encrypt_amount(&context, &pk_sender, Amount::from_micro_ccd(s), &mut csprng); diff --git a/rust-src/concordium_base/src/encrypted_transfers/proofs/generate_proofs.rs b/rust-src/concordium_base/src/encrypted_transfers/proofs/generate_proofs.rs index 903fbd128..5e79fc057 100644 --- a/rust-src/concordium_base/src/encrypted_transfers/proofs/generate_proofs.rs +++ b/rust-src/concordium_base/src/encrypted_transfers/proofs/generate_proofs.rs @@ -655,15 +655,18 @@ pub fn verify_sec_to_pub_trans( #[cfg(test)] mod test { + use ark_bls12_381::G1Projective; + + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; - // use rand::{rngs::ThreadRng, Rng}; - type SomeCurve = G1; + type SomeCurve = ArkGroup; + // Copied from common.rs in sigma_protocols since apparently it is not available pub fn generate_challenge_prefix(csprng: &mut R) -> Vec { // length of the challenge - let l = csprng.gen_range(0, 1000); + let l = csprng.gen_range(0..1000); let mut challenge_prefix = vec![0; l]; for v in challenge_prefix.iter_mut() { *v = csprng.gen(); @@ -675,13 +678,14 @@ mod test { #[test] fn test_enc_trans() { let mut csprng = thread_rng(); - let sk_sender: SecretKey = SecretKey::generate_all(&mut csprng); + let sk_sender: SecretKey = SecretKey::generate_all(&mut csprng); let pk_sender = PublicKey::from(&sk_sender); - let sk_receiver: SecretKey = SecretKey::generate(&pk_sender.generator, &mut csprng); + let sk_receiver: SecretKey = + SecretKey::generate(&pk_sender.generator, &mut csprng); let pk_receiver = PublicKey::from(&sk_receiver); let s = csprng.gen::(); // amount on account. - let a = csprng.gen_range(0, s); // amount to send + let a = csprng.gen_range(0..s); // amount to send let m = 2; // 2 chunks let n = 32; @@ -727,11 +731,11 @@ mod test { #[test] fn test_sec_to_pub() { let mut csprng = thread_rng(); - let sk: SecretKey = SecretKey::generate_all(&mut csprng); + let sk: SecretKey = SecretKey::generate_all(&mut csprng); let pk = PublicKey::from(&sk); let s = csprng.gen::(); // amount on account. - let a = csprng.gen_range(0, s); // amount to send + let a = csprng.gen_range(0..s); // amount to send let m = 2; // 2 chunks let n = 32; diff --git a/rust-src/concordium_base/src/id/account_holder.rs b/rust-src/concordium_base/src/id/account_holder.rs index 358a8d48d..fabfb7ea1 100644 --- a/rust-src/concordium_base/src/id/account_holder.rs +++ b/rust-src/concordium_base/src/id/account_holder.rs @@ -142,7 +142,7 @@ pub fn generate_pio>( let ip_ar_data = ip_ar_data .iter() - .zip(proof.response.r1.r2.responses.into_iter()) + .zip(proof.response.r1.r2.responses) .map(|((ar_id, f), w)| (*ar_id, f(w))) .collect::>(); @@ -216,7 +216,7 @@ pub fn generate_pio_v1>( let ip_ar_data = ip_ar_data .iter() - .zip(proof.response.r2.responses.into_iter()) + .zip(proof.response.r2.responses) .map(|((ar_id, f), w)| (*ar_id, f(w))) .collect::>(); @@ -1260,13 +1260,15 @@ mod tests { use crate::{ common::types::{KeyIndex, KeyPair}, - curve_arithmetic::Curve, + curve_arithmetic::{arkworks_instances::ArkGroup, Curve}, id::{constants::*, identity_provider::*, secret_sharing::Threshold, test::*}, pedersen_commitment::CommitmentKey as PedersenKey, }; + use ark_bls12_381::g1; + use ark_ec::short_weierstrass::Projective; use either::Either::Left; - type ExampleCurve = pairing::bls12_381::G1; + type ExampleCurve = ArkGroup>; const EXPIRY: TransactionTime = TransactionTime { seconds: 111111111111111111, @@ -1353,7 +1355,8 @@ mod tests { let num_ars = 4; let threshold = 3; let ar_base = ExampleCurve::generate(&mut csprng); - let (ars_infos, _ar_keys) = test_create_ars(&ar_base, num_ars, &mut csprng); + let ars = test_create_ars(&ar_base, num_ars, &mut csprng); + let ars_infos: BTreeMap> = ars.0; let ck = PedersenKey::generate(&mut csprng); let value = Value::::generate(&mut csprng); @@ -1416,8 +1419,9 @@ mod tests { num_ars, &acc_data, ); - let alist = test_create_attributes(); - let ver_ok = verify_credentials( + let alist: AttributeList<::ScalarField, AttributeKind> = + test_create_attributes(); + let ver_ok = verify_credentials::( &pio, context, &alist, diff --git a/rust-src/concordium_base/src/id/chain.rs b/rust-src/concordium_base/src/id/chain.rs index 6007621ef..758aa9a01 100644 --- a/rust-src/concordium_base/src/id/chain.rs +++ b/rust-src/concordium_base/src/id/chain.rs @@ -354,13 +354,16 @@ mod tests { use crate::{ common::types::{KeyIndex, KeyPair}, + curve_arithmetic::arkworks_instances::ArkGroup, id::{account_holder::*, constants::*, identity_provider::*, test::*}, }; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; use rand::*; use std::collections::btree_map::BTreeMap; use Either::{Left, Right}; + type SomeCurve = ArkGroup; + const EXPIRY: TransactionTime = TransactionTime { seconds: 111111111111111111, }; @@ -377,7 +380,7 @@ mod tests { ip_secret_key, ip_cdi_secret_key, } = test_create_ip_info(&mut csprng, num_ars, max_attrs); - let global_ctx = GlobalContext::::generate(String::from("genesis_string")); + let global_ctx = GlobalContext::::generate(String::from("genesis_string")); let (ars_infos, _) = test_create_ars(&global_ctx.on_chain_commitment_key.g, num_ars, &mut csprng); let id_use_data = test_create_id_use_data(&mut csprng); @@ -501,7 +504,7 @@ mod tests { ip_secret_key, .. // ip_cdi_secret_key is not used since we are testing the flow without initial account creation } = test_create_ip_info(&mut csprng, num_ars, max_attrs); - let global_ctx = GlobalContext::::generate(String::from("genesis_string")); + let global_ctx = GlobalContext::::generate(String::from("genesis_string")); let (ars_infos, _) = test_create_ars(&global_ctx.on_chain_commitment_key.g, num_ars, &mut csprng); let id_use_data = test_create_id_use_data(&mut csprng); @@ -601,7 +604,7 @@ mod tests { ip_secret_key, ip_cdi_secret_key, } = test_create_ip_info(&mut csprng, num_ars, max_attrs); - let global_ctx = GlobalContext::::generate(String::from("genesis_string")); + let global_ctx = GlobalContext::::generate(String::from("genesis_string")); let (ars_infos, _) = test_create_ars(&global_ctx.on_chain_commitment_key.g, num_ars, &mut csprng); let id_use_data = test_create_id_use_data(&mut csprng); diff --git a/rust-src/concordium_base/src/id/constants.rs b/rust-src/concordium_base/src/id/constants.rs index 8a8bae5ce..0dea25dd3 100644 --- a/rust-src/concordium_base/src/id/constants.rs +++ b/rust-src/concordium_base/src/id/constants.rs @@ -6,10 +6,11 @@ use crate::{ Buffer, Deserial, Get, ParseResult, Put, ReadBytesExt, SerdeDeserialize, SerdeSerialize, Serial, }, - curve_arithmetic::{Curve, Pairing}, + curve_arithmetic::{arkworks_instances::ArkGroup, Curve, Pairing}, }; use anyhow::bail; -use pairing::bls12_381::G1; +use ark_bls12_381::{G1Projective, G2Projective}; +use ark_ec::bls12::Bls12; use serde::{ de::{self, Visitor}, Deserializer, Serializer, @@ -18,12 +19,14 @@ use std::{fmt, io::Cursor, str::FromStr}; use thiserror::Error; /// Curve used by the anonymity revoker. -pub type ArCurve = pairing::bls12_381::G1; +pub type ArCurve = ArkGroup; +/// G2 group of the BLS12-381 curve +pub type BlsG2 = ArkGroup; /// Pairing used by the identity provider. -pub type IpPairing = pairing::bls12_381::Bls12; +pub type IpPairing = Bls12; /// Field used by the identity provider and anonymity revoker. -/// This isthe base field of both the ArCurve and the IpPairing. -pub type BaseField = ::ScalarField; +/// This is the scalar field of both the ArCurve and the IpPairing. +pub type BaseField = ::ScalarField; /// Index used to create the RegId of the initial credential. pub const INITIAL_CREDENTIAL_INDEX: u8 = 0; @@ -110,13 +113,13 @@ impl From for AttributeKind { fn from(x: u64) -> Self { AttributeKind(x.to_string()) } } -impl Attribute<::Scalar> for AttributeKind { - fn to_field_element(&self) -> ::Scalar { +impl Attribute< as Curve>::Scalar> for AttributeKind { + fn to_field_element(&self) -> as Curve>::Scalar { let mut buf = [0u8; 32]; let len = self.0.as_bytes().len(); buf[1 + (31 - len)..].copy_from_slice(self.0.as_bytes()); buf[0] = len as u8; // this should be valid because len <= 31 so the first two bits will be unset - <::Scalar as Deserial>::deserial(&mut Cursor::new(&buf)) + < as Curve>::Scalar as Deserial>::deserial(&mut Cursor::new(&buf)) .expect("31 bytes + length fits into a scalar.") } } diff --git a/rust-src/concordium_base/src/id/ffi.rs b/rust-src/concordium_base/src/id/ffi.rs index 8e86830a0..ee5f5de72 100644 --- a/rust-src/concordium_base/src/id/ffi.rs +++ b/rust-src/concordium_base/src/id/ffi.rs @@ -8,12 +8,13 @@ use super::{ use crate::{ bulletproofs::utils::Generators, common::{size_t, types::TransactionTime, *}, + curve_arithmetic::arkworks_instances::ArkGroup, ffi_helpers::*, pedersen_commitment::CommitmentKey as PedersenKey, }; use anyhow::Context; +use ark_bls12_381::G1Projective; use either::Either::{Left, Right}; -use pairing::bls12_381::{Bls12, G1}; use rand::thread_rng; use std::{ collections::BTreeMap, @@ -22,6 +23,9 @@ use std::{ str::from_utf8, }; +type Bls12 = ark_ec::bls12::Bls12; +type G1 = ArkGroup; + #[no_mangle] #[allow(clippy::not_unsafe_ptr_arg_deref)] extern "C" fn verify_initial_cdi_ffi( @@ -555,7 +559,7 @@ fn ip_info_create_helper( // Identity provider CDI verify key. let ip_cdi_verify_key = { let ed_buf = &mut slice_from_c_bytes!(cdi_verify_key_ptr, cdi_verify_key_len); - from_bytes::(ed_buf) + from_bytes::(ed_buf) .context("Unable to create PublicKey instance from byte array at cdi_verify_key_ptr.")? }; diff --git a/rust-src/concordium_base/src/id/id_proof_types.rs b/rust-src/concordium_base/src/id/id_proof_types.rs index 85318f498..1f05a2033 100644 --- a/rust-src/concordium_base/src/id/id_proof_types.rs +++ b/rust-src/concordium_base/src/id/id_proof_types.rs @@ -12,13 +12,15 @@ use crate::{ set_non_membership_proof::SetNonMembershipProof, }, common::*, - curve_arithmetic::Curve, + curve_arithmetic::{arkworks_instances::ArkGroup, Curve}, sigma_protocols::dlog::Response as DlogResponse, }; -use pairing::bls12_381::G1; +use ark_bls12_381::G1Projective; use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize}; use std::{collections::BTreeSet, convert::TryFrom, marker::PhantomData, str::FromStr}; +type G1 = ArkGroup; + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] pub enum ProofVersion { Version1, diff --git a/rust-src/concordium_base/src/id/id_prover.rs b/rust-src/concordium_base/src/id/id_prover.rs index de7957b4a..98bd73ea4 100644 --- a/rust-src/concordium_base/src/id/id_prover.rs +++ b/rust-src/concordium_base/src/id/id_prover.rs @@ -17,7 +17,6 @@ use crate::{ dlog::{Dlog, DlogSecret}, }, }; -use ed25519_dalek as ed25519; use sha2::{Digest, Sha256}; /// Function for producing a proof of a statement. @@ -197,10 +196,7 @@ pub fn prove_ownership_of_account( let sigs = data .keys .iter() - .map(|(&idx, kp)| { - let expanded_sk = ed25519::ExpandedSecretKey::from(&kp.secret); - (idx, expanded_sk.sign(to_sign, &kp.public).into()) - }) + .map(|(&idx, kp)| (idx, kp.sign(to_sign).into())) .collect(); AccountOwnershipProof { sigs } } diff --git a/rust-src/concordium_base/src/id/id_verifier.rs b/rust-src/concordium_base/src/id/id_verifier.rs index 9114a9e86..a89633f17 100644 --- a/rust-src/concordium_base/src/id/id_verifier.rs +++ b/rust-src/concordium_base/src/id/id_verifier.rs @@ -328,9 +328,10 @@ mod tests { use super::*; use crate::{ common::types::{KeyIndex, KeyPair}, + curve_arithmetic::arkworks_instances::ArkGroup, id::{constants::AttributeKind, id_prover::*}, }; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; use rand::*; use std::{ collections::{btree_map::BTreeMap, BTreeSet}, @@ -338,6 +339,8 @@ mod tests { marker::PhantomData, }; + type G1 = ArkGroup; + #[test] fn test_verify_account_ownership() { let mut csprng = thread_rng(); @@ -355,7 +358,8 @@ mod tests { let pub_data = cred_data.get_cred_key_info(); - let reg_id: G1 = Curve::hash_to_group(b"some_bytes"); + let reg_id: G1 = + Curve::hash_to_group(b"some_bytes").expect("Hashing to curve expected to succeed"); let account_address = account_address_from_registration_id(®_id); let challenge = b"13549686546546546854651357687354"; @@ -530,7 +534,8 @@ mod tests { #[test] fn test_verify_id_attributes_proofs() { - let point: G1 = Curve::hash_to_group(b"some_bytes"); + let point: G1 = + Curve::hash_to_group(b"some_bytes").expect("Hashing to curve expected to succeed"); let cmm_prf = Commitment(point); let cmm_max_accounts = Commitment(point); let cmm_cred_counter = Commitment(point); diff --git a/rust-src/concordium_base/src/id/identity_provider.rs b/rust-src/concordium_base/src/id/identity_provider.rs index e0b7fdfa8..cfb978642 100644 --- a/rust-src/concordium_base/src/id/identity_provider.rs +++ b/rust-src/concordium_base/src/id/identity_provider.rs @@ -10,6 +10,7 @@ use crate::{ random_oracle::RandomOracle, sigma_protocols::{com_enc_eq, com_eq, com_eq_different_groups, common::*, dlog}, }; +use ed25519_dalek::Signer as _; use rand::*; use sha2::{Digest, Sha256}; use std::collections::{BTreeMap, BTreeSet}; @@ -546,31 +547,24 @@ pub fn create_initial_cdi< cred_account: pub_info_for_ip.vk_acc, }; - let sig = sign_initial_cred_values(&cred_values, expiry, ip_info, ip_cdi_secret_key); + let sig = sign_initial_cred_values(&cred_values, expiry, ip_cdi_secret_key); InitialCredentialDeploymentInfo { values: cred_values, sig, } } -fn sign_initial_cred_values< - P: Pairing, - C: Curve, - AttributeType: Attribute, ->( +fn sign_initial_cred_values>( initial_cred_values: &InitialCredentialDeploymentValues, expiry: TransactionTime, - ip_info: &IpInfo

, ip_cdi_secret_key: &ed25519_dalek::SecretKey, ) -> IpCdiSignature { let mut hasher = Sha256::new(); hasher.update(&to_bytes(&expiry)); hasher.update(&to_bytes(&initial_cred_values)); let to_sign = hasher.finalize(); - let expanded_sk = ed25519_dalek::ExpandedSecretKey::from(ip_cdi_secret_key); - expanded_sk - .sign(to_sign.as_ref(), &ip_info.ip_cdi_verify_key) - .into() + let signing_key = ed25519_dalek::SigningKey::from(ip_cdi_secret_key); + signing_key.sign(to_sign.as_ref()).into() } pub fn compute_message>( @@ -685,7 +679,6 @@ mod tests { id::{account_holder::generate_id_recovery_request, constants::ArCurve, test::*}, pedersen_commitment::{CommitmentKey, Value as PedersenValue}, }; - use ff::Field; use std::collections::btree_map::BTreeMap; const EXPIRY: TransactionTime = TransactionTime { @@ -709,7 +702,7 @@ mod tests { let ck = CommitmentKey::::generate(&mut csprng); // Make degree-d polynomial - let d = csprng.gen_range(1, 10); + let d = csprng.gen_range(1..10); let mut coeffs = Vec::new(); let mut rands = Vec::new(); let mut values = Vec::new(); diff --git a/rust-src/concordium_base/src/id/secret_sharing.rs b/rust-src/concordium_base/src/id/secret_sharing.rs index 6188a5ca1..ce18cd52a 100644 --- a/rust-src/concordium_base/src/id/secret_sharing.rs +++ b/rust-src/concordium_base/src/id/secret_sharing.rs @@ -197,10 +197,14 @@ pub fn reveal_in_group + Copy, C: Curve>(shares: &[(P, C)]) -> C { #[cfg(test)] mod test { + use crate::curve_arithmetic::arkworks_instances::{ArkField, ArkGroup}; + use super::*; - use pairing::bls12_381::{Fr, G1}; + use ark_bls12_381::{Fr, G1Projective}; use rand::seq::SliceRandom; + type G1 = ArkGroup; + // Test Lagrange interpolation polynomials at x={0,1} #[test] pub fn test_lagrange() { @@ -233,7 +237,7 @@ mod test { xs.shuffle(&mut csprng); // select random threshold; - let t = csprng.gen_range(1, xs.len() + 1); + let t = csprng.gen_range(1..xs.len() + 1); let shared = share::(&secret, xs.into_iter(), Threshold(t as u8), &mut csprng); @@ -255,7 +259,7 @@ mod test { .mul_by_scalar(&::generate_non_zero_scalar(&mut csprng)); let secret = ::generate_scalar(&mut csprng); let secret_point = generator.mul_by_scalar(&secret); - let threshold = csprng.gen_range(1, i + 1); + let threshold = csprng.gen_range(1..i + 1); let mut xs = (1..=i).collect::>(); xs.shuffle(&mut csprng); @@ -278,7 +282,7 @@ mod test { .iter() .map(|(n, s)| (*n, generator.mul_by_scalar(s))) .collect::>(); - let revealed_data: Fr = reveal::<_, G1>(sufficient_sample); + let revealed_data: ArkField = reveal::<_, G1>(sufficient_sample); assert_eq!(revealed_data, secret); let revealed_data_point: G1 = reveal_in_group::<_, G1>(&sufficient_sample_points); assert_eq!(revealed_data_point, secret_point); @@ -300,7 +304,7 @@ mod test { let rand_elm = shares.choose_mut(&mut csprng).unwrap(); rand_elm.1 = crate::curve_arithmetic::Value::generate(&mut csprng); - let revealed_data: Fr = reveal::<_, G1>(&shares); + let revealed_data: ArkField = reveal::<_, G1>(&shares); assert_ne!(revealed_data, secret); let sufficient_points_err = shares .iter() @@ -327,7 +331,7 @@ mod test { .iter() .map(|(n, s)| (*n, generator.mul_by_scalar(s))) .collect::>(); - let revealed_data: Fr = reveal::<_, G1>(insufficient_sample); + let revealed_data: ArkField = reveal::<_, G1>(insufficient_sample); assert_ne!(revealed_data, secret); let revealed_data_point: G1 = reveal_in_group::<_, G1>(&insufficient_sample_points); assert_ne!(revealed_data_point, secret_point); diff --git a/rust-src/concordium_base/src/id/test.rs b/rust-src/concordium_base/src/id/test.rs index 6d4e22570..e40b74655 100644 --- a/rust-src/concordium_base/src/id/test.rs +++ b/rust-src/concordium_base/src/id/test.rs @@ -16,6 +16,7 @@ use crate::{ types::*, }, }; +use ed25519::SigningKey; use ed25519_dalek as ed25519; use either::Either::Left; use rand::*; @@ -60,7 +61,7 @@ pub fn test_create_ars( } /// Create identity provider with #num_ars ARs to be used by tests -pub fn test_create_ip_info( +pub fn test_create_ip_info( csprng: &mut T, num_ars: u8, max_attrs: u8, @@ -70,9 +71,10 @@ pub fn test_create_ip_info( let ps_len = (5 + num_ars + max_attrs) as usize; let ip_secret_key = crate::ps_sig::SecretKey::::generate(ps_len, csprng); let ip_verify_key = crate::ps_sig::PublicKey::from(&ip_secret_key); - let keypair = ed25519::Keypair::generate(csprng); - let ip_cdi_verify_key = keypair.public; - let ip_cdi_secret_key = keypair.secret; + let signing = SigningKey::generate(csprng); + let secret = signing.to_bytes(); + let ip_cdi_verify_key = signing.verifying_key(); + let ip_cdi_secret_key = secret; // Return IpData with public and private keys. IpData { diff --git a/rust-src/concordium_base/src/id/types.rs b/rust-src/concordium_base/src/id/types.rs index 55bf2ecf7..face43556 100644 --- a/rust-src/concordium_base/src/id/types.rs +++ b/rust-src/concordium_base/src/id/types.rs @@ -1079,7 +1079,7 @@ pub struct IpInfo { serialize_with = "base16_encode", deserialize_with = "base16_decode" )] - pub ip_cdi_verify_key: ed25519::PublicKey, + pub ip_cdi_verify_key: ed25519::VerifyingKey, } /// Collection of identity providers. @@ -1370,9 +1370,10 @@ impl> Deserial for Policy SerdeDeserialize<'de> for VerifyKey { } } -impl From for VerifyKey { - fn from(pk: ed25519::PublicKey) -> Self { VerifyKey::Ed25519VerifyKey(pk) } +impl From for VerifyKey { + fn from(pk: ed25519::VerifyingKey) -> Self { VerifyKey::Ed25519VerifyKey(pk) } } -impl From<&ed25519::Keypair> for VerifyKey { - fn from(kp: &ed25519::Keypair) -> Self { VerifyKey::Ed25519VerifyKey(kp.public) } +impl From<&ed25519::SigningKey> for VerifyKey { + fn from(kp: &ed25519::SigningKey) -> Self { VerifyKey::Ed25519VerifyKey(kp.verifying_key()) } } impl From<&KeyPair> for VerifyKey { - fn from(kp: &KeyPair) -> Self { VerifyKey::Ed25519VerifyKey(kp.public) } + fn from(kp: &KeyPair) -> Self { VerifyKey::Ed25519VerifyKey(kp.public()) } } /// Compare byte representation. @@ -1894,19 +1895,21 @@ impl GlobalContext { /// amount, and a fixed seed. pub fn generate_from_seed(genesis_string: String, n: usize, seed: &[u8]) -> Self { // initialize the first generator from pi digits. - let g = C::hash_to_group(seed); + let g = C::hash_to_group(seed).expect("Hashing to curve expected to succeed"); // generate next generator by hashing the previous one - let h = C::hash_to_group(&to_bytes(&g)); + let h = C::hash_to_group(&to_bytes(&g)).expect("Hashing to curve expected to succeed"); let cmm_key = PedersenKey { g, h }; let mut generators = Vec::with_capacity(n); let mut generator = h; for _ in 0..n { - generator = C::hash_to_group(&to_bytes(&generator)); + generator = C::hash_to_group(&to_bytes(&generator)) + .expect("Hashing to curve expected to succeed"); let g = generator; - generator = C::hash_to_group(&to_bytes(&generator)); + generator = C::hash_to_group(&to_bytes(&generator)) + .expect("Hashing to curve expected to succeed"); let h = generator; generators.push((g, h)); } @@ -2064,7 +2067,7 @@ impl From for AccountPublicKeys { inner_map.insert( u8::from(key_index), concordium_contracts_common::PublicKey::Ed25519(PublicKeyEd25519( - *public_key.public.as_bytes(), + *public_key.public().as_bytes(), )), ); } @@ -2130,7 +2133,7 @@ impl AccountKeys { let cred_sigs = cred_keys .keys .iter() - .map(|(ki, kp)| (*ki, kp.sign(msg))) + .map(|(ki, kp)| (*ki, kp.sign(msg).into())) .collect::>(); signatures.insert(*ci, cred_sigs); } @@ -2151,9 +2154,7 @@ impl AccountKeys { ( u8::from(*ki), concordium_contracts_common::Signature::Ed25519(SignatureEd25519( - // Unwrap is safe since the conversion is between signature types - // represented by byte arrays of the same length [u8, u64]. - kp.sign(msg).sig.try_into().unwrap(), + kp.sign(msg).to_bytes(), )), ) }) @@ -2222,7 +2223,7 @@ impl PublicCredentialData for CredentialData { fn get_public_keys(&self) -> BTreeMap { self.keys .iter() - .map(|(&idx, kp)| (idx, VerifyKey::Ed25519VerifyKey(kp.public))) + .map(|(&idx, kp)| (idx, kp.into())) .collect() } } @@ -2240,10 +2241,7 @@ impl CredentialDataWithSigning for CredentialData { ); self.keys .iter() - .map(|(&idx, kp)| { - let expanded_sk = ed25519::ExpandedSecretKey::from(&kp.secret); - (idx, expanded_sk.sign(&to_sign, &kp.public).into()) - }) + .map(|(&idx, kp)| (idx, kp.sign(&to_sign).into())) .collect() } } @@ -2263,7 +2261,7 @@ impl PublicInitialAccountData for InitialAccountData { fn get_public_keys(&self) -> BTreeMap { self.keys .iter() - .map(|(&idx, kp)| (idx, VerifyKey::Ed25519VerifyKey(kp.public))) + .map(|(&idx, kp)| (idx, kp.into())) .collect() } } @@ -2276,10 +2274,7 @@ impl InitialAccountDataWithSigning for InitialAccountData { let to_sign = Sha256::digest(to_bytes(pub_info_for_ip)); self.keys .iter() - .map(|(&idx, kp)| { - let expanded_sk = ed25519::ExpandedSecretKey::from(&kp.secret); - (idx, expanded_sk.sign(&to_sign, &kp.public).into()) - }) + .map(|(&idx, kp)| (idx, kp.sign(&to_sign).into())) .collect() } } @@ -2648,7 +2643,7 @@ mod tests { use rand::thread_rng; let mut csprng = thread_rng(); - let keypair = ed25519::Keypair::generate(&mut csprng); + let keypair = ed25519::SigningKey::generate(&mut csprng); for _ in 0..1000 { let message: &[u8] = b"test"; let signature: AccountOwnershipSignature = keypair.sign(message).into(); @@ -2677,17 +2672,13 @@ mod tests { // Get public key from map let credential_keys = &keypairs.keys[&CredentialIndex { index: 0 }]; let key_pair = &credential_keys.keys[&KeyIndex(0)]; - let public_key = key_pair.public; + let public_key = key_pair.public(); // Check that signature is valid match signature { concordium_std::Signature::Ed25519(signature) => { public_key - .verify( - message, - &ed25519_dalek::Signature::from_bytes(&signature.0) - .expect("Should be able to convert signature"), - ) + .verify(message, &ed25519_dalek::Signature::from_bytes(&signature.0)) .expect("Should be a valid signature"); } _ => assert!(false, "Could not get signature"), diff --git a/rust-src/concordium_base/src/id/utils.rs b/rust-src/concordium_base/src/id/utils.rs index a541f219c..24ad8833e 100644 --- a/rust-src/concordium_base/src/id/utils.rs +++ b/rust-src/concordium_base/src/id/utils.rs @@ -324,15 +324,15 @@ where #[cfg(test)] mod tests { use super::*; - use crate::common::to_bytes; - use pairing::bls12_381::Fr; + use crate::{common::to_bytes, curve_arithmetic::arkworks_instances::ArkField}; + use ark_bls12_381::Fr; use rand::{thread_rng, Rng}; use std::collections::BTreeMap; #[test] pub fn test_last_bit() { let ars = (1..10).map(ArIdentity::new).collect::>(); - let encoded = encode_ars::(&ars).expect("Encodign should succeed."); + let encoded = encode_ars::>(&ars).expect("Encodign should succeed."); // Field size of Fr is 254 bits, so what we expect is to have two scalars assert_eq!(encoded.len(), 2, "Encoded ARs should fit into two scalars."); let s1 = to_bytes(&encoded[0]); @@ -354,10 +354,10 @@ mod tests { for n in 1..50 { let mut xs = vec![ArIdentity::new(1); n]; for x in xs.iter_mut() { - *x = ArIdentity::new(csprng.gen_range(1, 100)); + *x = ArIdentity::new(csprng.gen_range(1..100)); } let set = xs.iter().copied().collect::>(); - let encoded = encode_ars::(&set).expect("Encoding should succeed."); + let encoded = encode_ars::>(&set).expect("Encoding should succeed."); if let Some(set_ex) = seen.insert(encoded.clone(), set.clone()) { assert_eq!(set, set_ex); } diff --git a/rust-src/concordium_base/src/lib.rs b/rust-src/concordium_base/src/lib.rs index 9c6e180e5..4bebcfd4c 100644 --- a/rust-src/concordium_base/src/lib.rs +++ b/rust-src/concordium_base/src/lib.rs @@ -35,7 +35,7 @@ pub mod dodis_yampolskiy_prf; /// We expose the `PublicKey`, `SecretKey`, and `Signature` from the third-party /// `ed25519_dalek` crate here because these types appear in Concordium's API. pub mod ed25519 { - pub use ed25519_dalek::{PublicKey, SecretKey, Signature}; + pub use ed25519_dalek::{SecretKey, Signature, VerifyingKey as PublicKey}; } #[cfg(feature = "ffi")] diff --git a/rust-src/concordium_base/src/pedersen_commitment/commitment.rs b/rust-src/concordium_base/src/pedersen_commitment/commitment.rs index a2ecfde5c..ebb24024f 100644 --- a/rust-src/concordium_base/src/pedersen_commitment/commitment.rs +++ b/rust-src/concordium_base/src/pedersen_commitment/commitment.rs @@ -40,9 +40,14 @@ impl std::borrow::Borrow for Commitment { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1, G2}; + use ark_bls12_381::{G1Projective, G2Projective}; use rand::*; + type G1 = ArkGroup; + type G2 = ArkGroup; + impl Commitment { pub fn generate(csprng: &mut T) -> Commitment { Commitment(C::generate(csprng)) } } diff --git a/rust-src/concordium_base/src/pedersen_commitment/key.rs b/rust-src/concordium_base/src/pedersen_commitment/key.rs index c74f66fb7..27d756ba2 100644 --- a/rust-src/concordium_base/src/pedersen_commitment/key.rs +++ b/rust-src/concordium_base/src/pedersen_commitment/key.rs @@ -147,8 +147,12 @@ impl VecCommitmentKey { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1Affine, G2Affine, G1, G2}; + use ark_bls12_381::{G1Projective, G2Projective}; + type G1 = ArkGroup; + type G2 = ArkGroup; macro_rules! macro_test_key_byte_conversion { ($function_name:ident, $curve_type:path) => { @@ -166,9 +170,9 @@ mod tests { }; } - macro_test_key_byte_conversion!(key_byte_conversion_bls12_381_g1_affine, G1Affine); + macro_test_key_byte_conversion!(key_byte_conversion_bls12_381_g1_projective, G1); - macro_test_key_byte_conversion!(key_byte_conversion_bls12_381_g2_affine, G2Affine); + macro_test_key_byte_conversion!(key_byte_conversion_bls12_381_g2_projective, G2); macro_rules! macro_test_commit_open { ($function_name:ident, $curve_type:path) => { @@ -217,15 +221,11 @@ mod tests { }; } - macro_test_commit_open!(commit_open_bls12_381_g1_affine, G1Affine); macro_test_commit_open!(commit_open_bls12_381_g1_projectitve, G1); - macro_test_commit_open!(commit_open_bls12_381_g2_affine, G2Affine); macro_test_commit_open!(commit_open_bls12_381_g2_projective, G2); - macro_test_commit_open_vec!(vec_commit_open_bls12_381_g1_affine, G1Affine); macro_test_commit_open_vec!(vec_commit_open_bls12_381_g1_projective, G1); - macro_test_commit_open_vec!(vec_commit_open_bls12_381_g2_affine, G2Affine); macro_test_commit_open_vec!(vec_commit_open_bls12_381_g2_projective, G2); } diff --git a/rust-src/concordium_base/src/pedersen_commitment/randomness.rs b/rust-src/concordium_base/src/pedersen_commitment/randomness.rs index dae67094e..e09f5a531 100644 --- a/rust-src/concordium_base/src/pedersen_commitment/randomness.rs +++ b/rust-src/concordium_base/src/pedersen_commitment/randomness.rs @@ -79,8 +79,12 @@ impl Randomness { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1Affine, G2Affine}; + use ark_bls12_381::{G1Projective, G2Projective}; + type G1 = ArkGroup; + type G2 = ArkGroup; macro_rules! macro_test_randomness_to_byte_conversion { ($function_name:ident, $curve_type:path) => { #[test] @@ -98,12 +102,12 @@ mod tests { } macro_test_randomness_to_byte_conversion!( - randomness_to_byte_conversion_bls12_381_g1_affine, - G1Affine + randomness_to_byte_conversion_bls12_381_g1_projective, + G1 ); macro_test_randomness_to_byte_conversion!( - randomness_to_byte_conversion_bls12_381_g2_affine, - G2Affine + randomness_to_byte_conversion_bls12_381_g2_projective, + G2 ); } diff --git a/rust-src/concordium_base/src/ps_sig/known_message.rs b/rust-src/concordium_base/src/ps_sig/known_message.rs index 17bc245d1..aadfeb4d8 100644 --- a/rust-src/concordium_base/src/ps_sig/known_message.rs +++ b/rust-src/concordium_base/src/ps_sig/known_message.rs @@ -33,7 +33,8 @@ impl KnownMessage { #[cfg(test)] mod tests { use super::*; - use pairing::bls12_381::Bls12; + + type Bls12 = ark_ec::models::bls12::Bls12; macro_rules! macro_test_message_to_byte_conversion { ($function_name:ident, $pairing_type:path) => { diff --git a/rust-src/concordium_base/src/ps_sig/public.rs b/rust-src/concordium_base/src/ps_sig/public.rs index ba798ce95..4789966e3 100644 --- a/rust-src/concordium_base/src/ps_sig/public.rs +++ b/rust-src/concordium_base/src/ps_sig/public.rs @@ -103,7 +103,7 @@ impl From<&SecretKey> for PublicKey { #[cfg(test)] mod tests { use super::*; - use pairing::bls12_381::Bls12; + type Bls12 = ark_ec::models::bls12::Bls12; macro_rules! macro_test_public_key_to_byte_conversion { ($function_name:ident, $pairing_type:path) => { diff --git a/rust-src/concordium_base/src/ps_sig/secret.rs b/rust-src/concordium_base/src/ps_sig/secret.rs index 17a07d9a5..2268b06bd 100644 --- a/rust-src/concordium_base/src/ps_sig/secret.rs +++ b/rust-src/concordium_base/src/ps_sig/secret.rs @@ -99,7 +99,7 @@ impl SecretKey { #[cfg(test)] mod tests { use super::*; - use pairing::bls12_381::Bls12; + type Bls12 = ark_ec::models::bls12::Bls12; macro_rules! macro_test_secret_key_to_byte_conversion { ($function_name:ident, $pairing_type:path) => { diff --git a/rust-src/concordium_base/src/ps_sig/signature.rs b/rust-src/concordium_base/src/ps_sig/signature.rs index 5d11a5023..08d1a4c83 100644 --- a/rust-src/concordium_base/src/ps_sig/signature.rs +++ b/rust-src/concordium_base/src/ps_sig/signature.rs @@ -65,7 +65,7 @@ impl Signature { #[cfg(test)] mod tests { use super::*; - use pairing::bls12_381::Bls12; + type Bls12 = ark_ec::models::bls12::Bls12; macro_rules! macro_test_signature_to_byte_conversion { ($function_name:ident, $pairing_type:path) => { diff --git a/rust-src/concordium_base/src/ps_sig/unknown_message.rs b/rust-src/concordium_base/src/ps_sig/unknown_message.rs index eb465e7af..ac4b7567e 100644 --- a/rust-src/concordium_base/src/ps_sig/unknown_message.rs +++ b/rust-src/concordium_base/src/ps_sig/unknown_message.rs @@ -75,7 +75,7 @@ impl UnknownMessage { #[cfg(test)] mod tests { use super::*; - use pairing::bls12_381::Bls12; + type Bls12 = ark_ec::models::bls12::Bls12; macro_rules! macro_test_unknown_message_to_byte_conversion { ($function_name:ident, $pairing_type:path) => { diff --git a/rust-src/concordium_base/src/sigma_protocols/aggregate_dlog.rs b/rust-src/concordium_base/src/sigma_protocols/aggregate_dlog.rs index 6890df4ed..a2349cde7 100644 --- a/rust-src/concordium_base/src/sigma_protocols/aggregate_dlog.rs +++ b/rust-src/concordium_base/src/sigma_protocols/aggregate_dlog.rs @@ -119,10 +119,14 @@ impl SigmaProtocol for AggregateDlog { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; use rand::{thread_rng, Rng}; + type G1 = ArkGroup; + #[test] pub fn test_aggregate_dlog_correctness() { let mut csprng = thread_rng(); @@ -152,7 +156,7 @@ mod tests { prove(&mut ro.split(), &agg, secret, csprng).expect("Input data is valid."); // Construct invalid parameters - let index_wrong_coeff: usize = csprng.gen_range(0, i); + let index_wrong_coeff: usize = csprng.gen_range(0..i); let mut wrong_ro = RandomOracle::domain(generate_challenge_prefix(csprng)); let wrong_public = G1::generate(csprng); diff --git a/rust-src/concordium_base/src/sigma_protocols/com_enc_eq.rs b/rust-src/concordium_base/src/sigma_protocols/com_enc_eq.rs index 920c42d46..59e8bf7d3 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_enc_eq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_enc_eq.rs @@ -200,9 +200,13 @@ impl SigmaProtocol for ComEncEq { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; use crate::elgamal::{Message, SecretKey as ElgamalSecretKey}; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; + + type G1 = ArkGroup; #[test] pub fn test_com_enc_eq_correctness() { diff --git a/rust-src/concordium_base/src/sigma_protocols/com_eq.rs b/rust-src/concordium_base/src/sigma_protocols/com_eq.rs index 95c9b82e6..1a555c9eb 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_eq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_eq.rs @@ -153,8 +153,13 @@ impl> SigmaProtocol for ComEq { #[cfg(test)] mod test { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1, G2}; + use ark_bls12_381::{G1Projective, G2Projective}; + + type G1 = ArkGroup; + type G2 = ArkGroup; #[test] pub fn test_com_eq_correctness() { diff --git a/rust-src/concordium_base/src/sigma_protocols/com_eq_different_groups.rs b/rust-src/concordium_base/src/sigma_protocols/com_eq_different_groups.rs index 960a40bfd..1a7af388e 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_eq_different_groups.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_eq_different_groups.rs @@ -163,8 +163,13 @@ impl> SigmaProtocol for ComEqDiffGroup #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::{G1, G2}; + use ark_bls12_381::{G1Projective, G2Projective}; + + type G1 = ArkGroup; + type G2 = ArkGroup; #[test] pub fn test_com_eq_diff_grps_correctness() { diff --git a/rust-src/concordium_base/src/sigma_protocols/com_eq_sig.rs b/rust-src/concordium_base/src/sigma_protocols/com_eq_sig.rs index ddd414619..20d207231 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_eq_sig.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_eq_sig.rs @@ -263,7 +263,7 @@ impl> SigmaProtocol for ComEqSig

> SigmaProtocol for ComEqSig

; + type Bls12 = ark_ec::models::bls12::Bls12; #[test] #[allow(non_snake_case)] @@ -343,7 +351,7 @@ mod tests { { if !wrong_ces.commitments.is_empty() { - let idx = csprng.gen_range(0, wrong_ces.commitments.len()); + let idx = csprng.gen_range(0..wrong_ces.commitments.len()); let tmp = wrong_ces.commitments[idx]; wrong_ces.commitments[idx] = wrong_ces .comm_key diff --git a/rust-src/concordium_base/src/sigma_protocols/com_ineq.rs b/rust-src/concordium_base/src/sigma_protocols/com_ineq.rs index 12a92895c..3e32305b3 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_ineq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_ineq.rs @@ -131,9 +131,13 @@ pub fn verify_com_ineq( #[cfg(test)] mod tests { + use crate::id::constants::{ArCurve, BaseField}; + use super::*; - use ff::PrimeField; - use pairing::bls12_381::{Fr, G1}; + use std::str::FromStr; + + type G1 = ArCurve; + type Fr = BaseField; #[test] fn test_com_ineq_correctness() { diff --git a/rust-src/concordium_base/src/sigma_protocols/com_lin.rs b/rust-src/concordium_base/src/sigma_protocols/com_lin.rs index 217d2f5bc..e0d9ad16a 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_lin.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_lin.rs @@ -217,12 +217,15 @@ impl SigmaProtocol for ComLin { #[allow(non_snake_case)] #[cfg(test)] mod tests { + use crate::id::constants::{ArCurve, BaseField}; + use super::*; - use ff::PrimeField; - use pairing::bls12_381::{Fr, G1}; - // use pairing::bls12_381::G1; + use crate::curve_arithmetic::PrimeField; use rand::thread_rng; - // use std::convert::TryInto; + use std::str::FromStr; + + type G1 = ArCurve; + type Fr = BaseField; #[test] pub fn test_com_lin_correctness() { diff --git a/rust-src/concordium_base/src/sigma_protocols/com_mult.rs b/rust-src/concordium_base/src/sigma_protocols/com_mult.rs index 538a6c4e8..ac375247c 100644 --- a/rust-src/concordium_base/src/sigma_protocols/com_mult.rs +++ b/rust-src/concordium_base/src/sigma_protocols/com_mult.rs @@ -172,10 +172,14 @@ impl SigmaProtocol for ComMult { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; use rand::thread_rng; + type G1 = ArkGroup; + #[test] pub fn test_com_mult_correctness() { let mut csprng = thread_rng(); diff --git a/rust-src/concordium_base/src/sigma_protocols/common.rs b/rust-src/concordium_base/src/sigma_protocols/common.rs index 77ff80eb2..92029f48d 100644 --- a/rust-src/concordium_base/src/sigma_protocols/common.rs +++ b/rust-src/concordium_base/src/sigma_protocols/common.rs @@ -339,7 +339,7 @@ pub fn verify( /// Generate a random challenge prefix of random length used for testing. pub fn generate_challenge_prefix(csprng: &mut R) -> Vec { // length of the challenge - let l = csprng.gen_range(0, 1000); + let l = csprng.gen_range(0..1000); let mut challenge_prefix = vec![0; l]; for v in challenge_prefix.iter_mut() { *v = csprng.gen(); diff --git a/rust-src/concordium_base/src/sigma_protocols/dlog.rs b/rust-src/concordium_base/src/sigma_protocols/dlog.rs index 5d8949bc9..f6ac0a1ae 100644 --- a/rust-src/concordium_base/src/sigma_protocols/dlog.rs +++ b/rust-src/concordium_base/src/sigma_protocols/dlog.rs @@ -100,8 +100,12 @@ impl SigmaProtocol for Dlog { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; + + type G1 = ArkGroup; #[test] pub fn test_dlog_correctness() { diff --git a/rust-src/concordium_base/src/sigma_protocols/dlogaggequal.rs b/rust-src/concordium_base/src/sigma_protocols/dlogaggequal.rs index ede9fc3d0..f984ccb4a 100644 --- a/rust-src/concordium_base/src/sigma_protocols/dlogaggequal.rs +++ b/rust-src/concordium_base/src/sigma_protocols/dlogaggequal.rs @@ -147,14 +147,19 @@ impl SigmaProtocol for DlogAndAggregateDlogsEqual { #[cfg(test)] mod test { use super::*; - use crate::curve_arithmetic::multiexp; - use ff::PrimeField; - use pairing::bls12_381::{Fr, G1}; + use crate::{ + curve_arithmetic::multiexp, + id::constants::{ArCurve, BaseField}, + }; use rand::*; + use std::str::FromStr; + + type G1 = ArCurve; + type Fr = BaseField; pub fn generate_challenge_prefix(csprng: &mut R) -> Vec { // length of the challenge - let l = csprng.gen_range(0, 1000); + let l = csprng.gen_range(0..1000); let mut challenge_prefix = vec![0; l]; for v in challenge_prefix.iter_mut() { *v = csprng.gen(); diff --git a/rust-src/concordium_base/src/sigma_protocols/dlogeq.rs b/rust-src/concordium_base/src/sigma_protocols/dlogeq.rs index f5aff2517..9c83b4f92 100644 --- a/rust-src/concordium_base/src/sigma_protocols/dlogeq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/dlogeq.rs @@ -78,14 +78,20 @@ impl SigmaProtocol for DlogEqual { #[cfg(test)] mod test { use super::*; - use crate::curve_arithmetic::Value; - use ff::PrimeField; - use pairing::bls12_381::{Fr, G1}; + use crate::{ + curve_arithmetic::Value, + id::constants::{ArCurve, BaseField}, + }; use rand::*; + use std::str::FromStr; + + type G1 = ArCurve; + type Fr = BaseField; + pub fn generate_challenge_prefix(csprng: &mut R) -> Vec { // length of the challenge - let l = csprng.gen_range(0, 1000); + let l = csprng.gen_range(0..1000); let mut challenge_prefix = vec![0; l]; for v in challenge_prefix.iter_mut() { *v = csprng.gen(); diff --git a/rust-src/concordium_base/src/sigma_protocols/enc_trans.rs b/rust-src/concordium_base/src/sigma_protocols/enc_trans.rs index 5efc601e7..af1e1ff26 100644 --- a/rust-src/concordium_base/src/sigma_protocols/enc_trans.rs +++ b/rust-src/concordium_base/src/sigma_protocols/enc_trans.rs @@ -364,12 +364,15 @@ impl SigmaProtocol for EncTrans { mod tests { use super::*; use crate::{ + curve_arithmetic::arkworks_instances::ArkGroup, elgamal::{PublicKey, Randomness, SecretKey}, pedersen_commitment::{Commitment, CommitmentKey}, }; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; use rand::Rng; + type G1 = ArkGroup; + impl EncTrans { fn with_valid_data( rng: &mut R, @@ -391,7 +394,7 @@ mod tests { coeff: [S.0, encr_exp_base], }; - let a = rng.gen_range(0, s); // amount to send + let a = rng.gen_range(0..s); // amount to send let s_prime = s - a; let a_chunks = CHUNK_SIZE.u64_to_chunks(a); let s_prime_chunks = CHUNK_SIZE.u64_to_chunks(s_prime); @@ -475,7 +478,7 @@ mod tests { fn generate_challenge_prefix(csprng: &mut R) -> Vec { // length of the challenge - let l = csprng.gen_range(0, 1000); + let l = csprng.gen_range(0..1000); let mut challenge_prefix = vec![0; l]; for v in challenge_prefix.iter_mut() { *v = csprng.gen(); diff --git a/rust-src/concordium_base/src/sigma_protocols/sigma_test.rs b/rust-src/concordium_base/src/sigma_protocols/sigma_test.rs index 211ad0981..97f1c1939 100644 --- a/rust-src/concordium_base/src/sigma_protocols/sigma_test.rs +++ b/rust-src/concordium_base/src/sigma_protocols/sigma_test.rs @@ -1,8 +1,13 @@ use crate::{ + curve_arithmetic::arkworks_instances::ArkGroup, random_oracle::RandomOracle, sigma_protocols::{com_enc_eq, com_eq_sig, common::*, dlog}, }; -use pairing::bls12_381::{Bls12, G1, G2}; +use ark_bls12_381::{G1Projective, G2Projective}; + +type G1 = ArkGroup; +type G2 = ArkGroup; +type Bls12 = ark_ec::models::bls12::Bls12; #[test] pub fn test_and() { diff --git a/rust-src/concordium_base/src/sigma_protocols/vcom_eq.rs b/rust-src/concordium_base/src/sigma_protocols/vcom_eq.rs index 6198c8640..dc21843cb 100644 --- a/rust-src/concordium_base/src/sigma_protocols/vcom_eq.rs +++ b/rust-src/concordium_base/src/sigma_protocols/vcom_eq.rs @@ -220,10 +220,14 @@ impl SigmaProtocol for VecComEq { #[cfg(test)] mod tests { + use crate::curve_arithmetic::arkworks_instances::ArkGroup; + use super::*; - use pairing::bls12_381::G1; + use ark_bls12_381::G1Projective; use rand::{thread_rng, Rng}; + type G1 = ArkGroup; + #[test] pub fn test_vcom_eq_correctness() { let mut csprng = thread_rng(); @@ -313,8 +317,8 @@ mod tests { i += 1; } let wrong_comm = Commitment::generate(csprng); - let index_wrong_comm: IndexType = csprng.gen_range(0, 6); - let index_wrong_gi: usize = csprng.gen_range(0, 10); + let index_wrong_comm: IndexType = csprng.gen_range(0..6); + let index_wrong_gi: usize = csprng.gen_range(0..10); let mut wrong_comms = comms.clone(); wrong_comms.insert(index_wrong_comm, wrong_comm); let mut wrong_gis = gis.clone(); diff --git a/rust-src/concordium_base/src/transactions.rs b/rust-src/concordium_base/src/transactions.rs index 24cd35c8b..0b70fb410 100644 --- a/rust-src/concordium_base/src/transactions.rs +++ b/rust-src/concordium_base/src/transactions.rs @@ -1391,7 +1391,7 @@ impl TransactionSigner for AccountKeys { for (ci, cred_keys) in iter { let cred_sigs = cred_keys .into_iter() - .map(|(ki, kp)| (*ki, kp.sign(hash_to_sign.as_ref()))) + .map(|(ki, kp)| (*ki, kp.sign(hash_to_sign.as_ref()).into())) .collect::>(); signatures.insert(*ci, cred_sigs); } @@ -1418,7 +1418,7 @@ impl TransactionSigner for BTreeMap for (ci, cred_keys) in self { let cred_sigs = cred_keys .iter() - .map(|(ki, kp)| (*ki, kp.sign(hash_to_sign.as_ref()))) + .map(|(ki, kp)| (*ki, kp.sign(hash_to_sign.as_ref()).into())) .collect::>(); signatures.insert(*ci, cred_sigs); } @@ -1470,7 +1470,7 @@ pub struct AccountAccessStructure { pub type AccountStructure<'a> = &'a [( CredentialIndex, SignatureThreshold, - &'a [(KeyIndex, ed25519_dalek::PublicKey)], + &'a [(KeyIndex, ed25519_dalek::VerifyingKey)], )]; impl AccountAccessStructure { @@ -1504,7 +1504,7 @@ impl AccountAccessStructure { /// Generate a new [`AccountAccessStructure`] with a single credential and /// public key, at credential and key indices 0. - pub fn singleton(public_key: ed25519_dalek::PublicKey) -> Self { + pub fn singleton(public_key: ed25519_dalek::VerifyingKey) -> Self { Self::new(AccountThreshold::ONE, &[( 0.into(), SignatureThreshold::ONE, @@ -1525,7 +1525,12 @@ impl From<&AccountKeys> for AccountAccessStructure { keys: v .keys .iter() - .map(|(ki, kp)| (*ki, VerifyKey::Ed25519VerifyKey(kp.public))) + .map(|(ki, kp)| { + ( + *ki, + VerifyKey::Ed25519VerifyKey(kp.as_ref().verifying_key()), + ) + }) .collect(), threshold: v.threshold, }) @@ -3179,11 +3184,11 @@ mod tests { fn test_transaction_signature_check() { let mut rng = rand::thread_rng(); let mut keys = BTreeMap::>::new(); - let bound: usize = rng.gen_range(1, 20); + let bound: usize = rng.gen_range(1..20); for _ in 0..bound { let c_idx = CredentialIndex::from(rng.gen::()); if keys.get(&c_idx).is_none() { - let inner_bound: usize = rng.gen_range(1, 20); + let inner_bound: usize = rng.gen_range(1..20); let mut cred_keys = BTreeMap::new(); for _ in 0..inner_bound { let k_idx = KeyIndex::from(rng.gen::()); @@ -3195,12 +3200,12 @@ mod tests { let hash = TransactionSignHash::new(rng.gen()); let sig = keys.sign_transaction_hash(&hash); let threshold = - AccountThreshold::try_from(rng.gen_range(1, (keys.len() + 1) as u8)).unwrap(); + AccountThreshold::try_from(rng.gen_range(1..(keys.len() + 1) as u8)).unwrap(); let pub_keys = keys .iter() .map(|(&ci, keys)| { let threshold = - SignatureThreshold::try_from(rng.gen_range(1, keys.len() + 1) as u8).unwrap(); + SignatureThreshold::try_from(rng.gen_range(1..keys.len() + 1) as u8).unwrap(); let keys = keys .iter() .map(|(&ki, kp)| (ki, VerifyKey::from(kp))) diff --git a/rust-src/concordium_base/src/web3id/did.rs b/rust-src/concordium_base/src/web3id/did.rs index 5841db7df..5a0707ed7 100644 --- a/rust-src/concordium_base/src/web3id/did.rs +++ b/rust-src/concordium_base/src/web3id/did.rs @@ -87,7 +87,7 @@ pub enum IdentifierType { parameter: OwnedParameter, }, /// Reference to a specific Ed25519 public key. - PublicKey { key: ed25519_dalek::PublicKey }, + PublicKey { key: ed25519_dalek::VerifyingKey }, /// Reference to a specific identity provider. Idp { idp_identity: IpIdentity }, } @@ -116,7 +116,7 @@ impl IdentifierType { /// If `self` is the [`PublicKey`](Self::PublicKey) variant then extract the /// public key, otherwise return [`None`]. - pub fn extract_public_key(&self) -> Option { + pub fn extract_public_key(&self) -> Option { let IdentifierType::PublicKey { key, } = self else { diff --git a/rust-src/concordium_base/src/web3id/mod.rs b/rust-src/concordium_base/src/web3id/mod.rs index 66b435293..03ee72165 100644 --- a/rust-src/concordium_base/src/web3id/mod.rs +++ b/rust-src/concordium_base/src/web3id/mod.rs @@ -106,8 +106,8 @@ impl + DeserializeOwned> TryFrom + serde::de::DeserializeOwned serde_json::from_value(get_field(&mut proof, "proofValue")?)?; anyhow::ensure!(proof_value.len() == statement.len()); - let proofs = statement.into_iter().zip(proof_value.into_iter()).collect(); + let proofs = statement.into_iter().zip(proof_value).collect(); Ok(Self::Account { created, network: issuer.network, @@ -540,7 +540,7 @@ impl + serde::de::DeserializeOwned serde_json::from_value(get_field(&mut proof, "proofValue")?)?; anyhow::ensure!(proof_value.len() == statement.len()); - let proofs = statement.into_iter().zip(proof_value.into_iter()).collect(); + let proofs = statement.into_iter().zip(proof_value).collect(); Ok(Self::Web3Id { created, @@ -631,12 +631,12 @@ pub struct Request> { /// An ed25519 public key tagged with a phantom type parameter based on its /// role, e.g., an owner of a credential or a revocation key. pub struct Ed25519PublicKey { - pub public_key: ed25519_dalek::PublicKey, + pub public_key: ed25519_dalek::VerifyingKey, phantom: PhantomData, } -impl From for Ed25519PublicKey { - fn from(value: ed25519_dalek::PublicKey) -> Self { Self::new(value) } +impl From for Ed25519PublicKey { + fn from(value: ed25519_dalek::VerifyingKey) -> Self { Self::new(value) } } impl serde::Serialize for Ed25519PublicKey { @@ -682,13 +682,17 @@ impl TryFrom<&str> for Ed25519PublicKey { type Error = Ed25519PublicKeyFromStrError; fn try_from(value: &str) -> Result { - let bytes = hex::decode(value)?; - Ok(Self::new(ed25519_dalek::PublicKey::from_bytes(&bytes)?)) + let bytes: [u8; 32] = hex::decode(value)?.try_into().map_err(|_| { + Self::Error::InvalidBytes(ed25519_dalek::SignatureError::from_source( + "Incorrect public key length.", + )) + })?; + Ok(Self::new(ed25519_dalek::VerifyingKey::from_bytes(&bytes)?)) } } impl Ed25519PublicKey { - pub fn new(public_key: ed25519_dalek::PublicKey) -> Self { + pub fn new(public_key: ed25519_dalek::VerifyingKey) -> Self { Self { public_key, phantom: PhantomData, @@ -743,7 +747,7 @@ impl crate::contracts_common::Deserial for Ed25519PublicKey { source: &mut R, ) -> crate::contracts_common::ParseResult { let public_key_bytes = <[u8; ed25519_dalek::PUBLIC_KEY_LENGTH]>::deserial(source)?; - let public_key = ed25519_dalek::PublicKey::from_bytes(&public_key_bytes) + let public_key = ed25519_dalek::VerifyingKey::from_bytes(&public_key_bytes) .map_err(|_| crate::contracts_common::ParseError {})?; Ok(Self { public_key, @@ -763,7 +767,7 @@ impl crate::common::Deserial for Ed25519PublicKey { fn deserial(source: &mut R) -> crate::common::ParseResult { use anyhow::Context; let public_key_bytes = <[u8; ed25519_dalek::PUBLIC_KEY_LENGTH]>::deserial(source)?; - let public_key = ed25519_dalek::PublicKey::from_bytes(&public_key_bytes) + let public_key = ed25519_dalek::VerifyingKey::from_bytes(&public_key_bytes) .context("Invalid public key.")?; Ok(Self { public_key, @@ -991,12 +995,12 @@ impl TryFrom for LinkingProof { /// credential. The intention is that this is implemented by ed25519 keypairs /// or hardware wallets. pub trait Web3IdSigner { - fn id(&self) -> ed25519_dalek::PublicKey; + fn id(&self) -> ed25519_dalek::VerifyingKey; fn sign(&self, msg: &impl AsRef<[u8]>) -> ed25519_dalek::Signature; } -impl Web3IdSigner for ed25519_dalek::Keypair { - fn id(&self) -> ed25519_dalek::PublicKey { self.public } +impl Web3IdSigner for ed25519_dalek::SigningKey { + fn id(&self) -> ed25519_dalek::VerifyingKey { self.verifying_key() } fn sign(&self, msg: &impl AsRef<[u8]>) -> ed25519_dalek::Signature { ed25519_dalek::Signer::sign(self, msg.as_ref()) @@ -1004,17 +1008,19 @@ impl Web3IdSigner for ed25519_dalek::Keypair { } impl Web3IdSigner for crate::common::types::KeyPair { - fn id(&self) -> ed25519_dalek::PublicKey { self.public } + fn id(&self) -> ed25519_dalek::VerifyingKey { self.public() } - fn sign(&self, msg: &impl AsRef<[u8]>) -> ed25519_dalek::Signature { self.secret.sign(msg) } + fn sign(&self, msg: &impl AsRef<[u8]>) -> ed25519_dalek::Signature { self.sign(msg.as_ref()) } } impl Web3IdSigner for ed25519_dalek::SecretKey { - fn id(&self) -> ed25519_dalek::PublicKey { self.into() } + fn id(&self) -> ed25519_dalek::VerifyingKey { + ed25519_dalek::SigningKey::from(self).verifying_key() + } fn sign(&self, msg: &impl AsRef<[u8]>) -> ed25519_dalek::Signature { - let expanded: ed25519_dalek::ExpandedSecretKey = self.into(); - expanded.sign(msg.as_ref(), &self.into()) + let expanded: ed25519_dalek::SigningKey = self.into(); + ed25519_dalek::Signer::sign(&expanded, msg.as_ref()) } } @@ -1160,8 +1166,9 @@ impl TryFrom anyhow::bail!("Only Web3 credentials are supported.") }; anyhow::ensure!(entrypoint == "credentialEntry", "Incorrect entrypoint."); - let holder_id = - CredentialHolderId::new(ed25519_dalek::PublicKey::from_bytes(parameter.as_ref())?); + let holder_id = CredentialHolderId::new(ed25519_dalek::VerifyingKey::from_bytes( + parameter.as_ref().try_into()?, + )?); // Just validate the issuer field. { @@ -1789,10 +1796,10 @@ mod tests { fn test_web3_only() -> anyhow::Result<()> { let mut rng = rand::thread_rng(); let challenge = Challenge::new(rng.gen()); - let signer_1 = ed25519_dalek::Keypair::generate(&mut rng); - let signer_2 = ed25519_dalek::Keypair::generate(&mut rng); - let issuer_1 = ed25519_dalek::Keypair::generate(&mut rng); - let issuer_2 = ed25519_dalek::Keypair::generate(&mut rng); + let signer_1 = ed25519_dalek::SigningKey::generate(&mut rng); + let signer_2 = ed25519_dalek::SigningKey::generate(&mut rng); + let issuer_1 = ed25519_dalek::SigningKey::generate(&mut rng); + let issuer_2 = ed25519_dalek::SigningKey::generate(&mut rng); let contract_1 = ContractAddress::new(1337, 42); let contract_2 = ContractAddress::new(1338, 0); let credential_statements = vec![ @@ -1806,7 +1813,7 @@ mod tests { .collect(), network: Network::Testnet, contract: contract_1, - credential: CredentialHolderId::new(signer_1.public), + credential: CredentialHolderId::new(signer_1.verifying_key()), statement: vec![ AtomicStatement::AttributeInRange { statement: AttributeInRangeStatement { @@ -1841,7 +1848,7 @@ mod tests { .collect(), network: Network::Testnet, contract: contract_2, - credential: CredentialHolderId::new(signer_2.public), + credential: CredentialHolderId::new(signer_2.verifying_key()), statement: vec![ AtomicStatement::AttributeInRange { statement: AttributeInRangeStatement { @@ -1904,7 +1911,7 @@ mod tests { ¶ms, &values_1, &randomness_1, - &CredentialHolderId::new(signer_1.public), + &CredentialHolderId::new(signer_1.verifying_key()), &issuer_1, contract_1, ) @@ -1944,7 +1951,7 @@ mod tests { ¶ms, &values_2, &randomness_2, - &CredentialHolderId::new(signer_2.public), + &CredentialHolderId::new(signer_2.verifying_key()), &issuer_2, contract_2, ) @@ -1963,10 +1970,10 @@ mod tests { let public = vec![ CredentialsInputs::Web3 { - issuer_pk: issuer_1.public.into(), + issuer_pk: issuer_1.verifying_key().into(), }, CredentialsInputs::Web3 { - issuer_pk: issuer_2.public.into(), + issuer_pk: issuer_2.verifying_key().into(), }, ]; anyhow::ensure!( @@ -2001,8 +2008,8 @@ mod tests { let params = GlobalContext::generate("Test".into()); let cred_id_exp = ArCurve::generate_scalar(&mut rng); let cred_id = CredentialRegistrationID::from_exponent(¶ms, cred_id_exp); - let signer_1 = ed25519_dalek::Keypair::generate(&mut rng); - let issuer_1 = ed25519_dalek::Keypair::generate(&mut rng); + let signer_1 = ed25519_dalek::SigningKey::generate(&mut rng); + let issuer_1 = ed25519_dalek::SigningKey::generate(&mut rng); let contract_1 = ContractAddress::new(1337, 42); let credential_statements = vec![ CredentialStatement::Web3Id { @@ -2015,7 +2022,7 @@ mod tests { .collect(), network: Network::Testnet, contract: contract_1, - credential: CredentialHolderId::new(signer_1.public), + credential: CredentialHolderId::new(signer_1.verifying_key()), statement: vec![ AtomicStatement::AttributeInRange { statement: AttributeInRangeStatement { @@ -2092,7 +2099,7 @@ mod tests { ¶ms, &values_1, &randomness_1, - &CredentialHolderId::new(signer_1.public), + &CredentialHolderId::new(signer_1.verifying_key()), &issuer_1, contract_1, ) @@ -2147,7 +2154,7 @@ mod tests { let public = vec![ CredentialsInputs::Web3 { - issuer_pk: issuer_1.public.into(), + issuer_pk: issuer_1.verifying_key().into(), }, CredentialsInputs::Account { commitments: commitments_2, @@ -2181,8 +2188,8 @@ mod tests { /// Basic test that conversion of Web3IdCredential from/to JSON works. fn test_credential_json() { let mut rng = rand::thread_rng(); - let signer = ed25519_dalek::Keypair::generate(&mut rng); - let issuer = ed25519_dalek::Keypair::generate(&mut rng); + let signer = ed25519_dalek::SigningKey::generate(&mut rng); + let issuer = ed25519_dalek::SigningKey::generate(&mut rng); let mut randomness = BTreeMap::new(); randomness.insert( 0.to_string(), @@ -2209,7 +2216,7 @@ mod tests { ); let cred = Web3IdCredential:: { - holder_id: signer.public.into(), + holder_id: signer.verifying_key().into(), network: Network::Testnet, registry: ContractAddress::new(3, 17), credential_type: [ @@ -2220,7 +2227,7 @@ mod tests { .into_iter() .collect(), credential_schema: "http://link/to/schema".into(), - issuer_key: issuer.public.into(), + issuer_key: issuer.verifying_key().into(), valid_from: chrono::Utc.timestamp_millis_opt(17).unwrap(), valid_until: chrono::Utc.timestamp_millis_opt(12345).earliest(), values, diff --git a/rust-src/ed25519_hd_key_derivation/Cargo.toml b/rust-src/ed25519_hd_key_derivation/Cargo.toml index 973f20717..fb8664732 100644 --- a/rust-src/ed25519_hd_key_derivation/Cargo.toml +++ b/rust-src/ed25519_hd_key_derivation/Cargo.toml @@ -10,7 +10,7 @@ hex = "0.4.3" hmac = "0.12.1" sha2 = "0.10.2" regex = "1.5.5" -ed25519-dalek = "=1.0" +ed25519-dalek = "2.0" thiserror = "1.0" [lib] diff --git a/rust-src/ed25519_hd_key_derivation/src/lib.rs b/rust-src/ed25519_hd_key_derivation/src/lib.rs index 9f74fb5f2..e1b1ed554 100644 --- a/rust-src/ed25519_hd_key_derivation/src/lib.rs +++ b/rust-src/ed25519_hd_key_derivation/src/lib.rs @@ -179,6 +179,8 @@ pub fn derive_from_parsed_path(parsed_path: &[u32], seed: &[u8]) -> Result Result { + ) -> Result { let secret_key = self.get_account_signing_key( identity_provider_index, identity_index, credential_counter, )?; - let public_key = PublicKey::from(&secret_key); + let signing = SigningKey::from_bytes(&secret_key); + let public_key = signing.verifying_key(); Ok(public_key) } @@ -286,24 +287,24 @@ impl ConcordiumHdWallet { 0, ])?; let keys = derive_from_parsed_path(&path, &self.seed)?; - Ok(SecretKey::from_bytes(&keys.private_key) - .expect("The byte array has correct length, so this cannot fail.")) + Ok(keys.private_key) } /// Get the public key for the verifiable credential with the given index. /// The public key is used to identify the specific verifiable credential /// within the registry contract. /// Note that this is just a convenience wrapper. The same can be achieved - /// by using [`PublicKey::from`] on the result of + /// by using [`VerifyingKey::from`] on the result of /// [`get_verifiable_credential_signing_key`](Self::get_verifiable_credential_signing_key) pub fn get_verifiable_credential_public_key( &self, issuer: ContractAddress, verifiable_credential_index: u32, - ) -> Result { + ) -> Result { let signing_key = self.get_verifiable_credential_signing_key(issuer, verifiable_credential_index)?; - let public_key = PublicKey::from(&signing_key); + let signing = SigningKey::from_bytes(&signing_key); + let public_key = signing.verifying_key(); Ok(public_key) } @@ -316,8 +317,7 @@ impl ConcordiumHdWallet { ) -> Result { let path = self.make_verifiable_credential_path(&[1])?; let keys = derive_from_parsed_path(&path, &self.seed)?; - Ok(SecretKey::from_bytes(&keys.private_key) - .expect("The byte array has correct length, so this cannot fail.")) + Ok(keys.private_key) } } @@ -435,10 +435,10 @@ mod tests { let signing_key = create_wallet(Net::Mainnet, TEST_SEED_1) .get_account_signing_key(0, 0, 0) .unwrap(); - let expanded_sk = ExpandedSecretKey::from(&signing_key); + let expanded_sk = SigningKey::from_bytes(&signing_key); let data_to_sign = hex::decode("abcd1234abcd5678").unwrap(); - let signature = expanded_sk.sign(&data_to_sign, &pk); + let signature = expanded_sk.sign(&data_to_sign); pk.verify(&data_to_sign, &signature).expect( "The public key should be able to verify the signature, otherwise the keys do not \ @@ -521,10 +521,10 @@ mod tests { .get_account_signing_key(0, 0, 0) .unwrap(); - let expanded_sk = ExpandedSecretKey::from(&signing_key); + let expanded_sk = SigningKey::from_bytes(&signing_key); let data_to_sign = hex::decode("abcd1234abcd5678").unwrap(); - let signature = expanded_sk.sign(&data_to_sign, &pk); + let signature = expanded_sk.sign(&data_to_sign); pk.verify(&data_to_sign, &signature).expect( "The public key should be able to verify the signature, otherwise the keys do not \ @@ -894,10 +894,10 @@ mod tests { let signing_key = wallet .get_verifiable_credential_signing_key(ContractAddress::new(1337, 0), 0) .unwrap(); - let expanded_sk = ExpandedSecretKey::from(&signing_key); + let expanded_sk = SigningKey::from_bytes(&signing_key); let data_to_sign = hex::decode("abcd1234abcd5678").unwrap(); - let signature = expanded_sk.sign(&data_to_sign, &public_key); + let signature = expanded_sk.sign(&data_to_sign); public_key.verify(&data_to_sign, &signature).expect( "The public key should be able to verify the signature, otherwise the keys do not \ @@ -959,10 +959,10 @@ mod tests { let signing_key = wallet .get_verifiable_credential_signing_key(ContractAddress::new(13, 0), 0) .unwrap(); - let expanded_sk = ExpandedSecretKey::from(&signing_key); + let expanded_sk = SigningKey::from_bytes(&signing_key); let data_to_sign = hex::decode("abcd1234abcd5678").unwrap(); - let signature = expanded_sk.sign(&data_to_sign, &public_key); + let signature = expanded_sk.sign(&data_to_sign); public_key.verify(&data_to_sign, &signature).expect( "The public key should be able to verify the signature, otherwise the keys do not \ diff --git a/rust-src/keygen_bls/Cargo.toml b/rust-src/keygen_bls/Cargo.toml index a10d8ba2f..04621bae8 100644 --- a/rust-src/keygen_bls/Cargo.toml +++ b/rust-src/keygen_bls/Cargo.toml @@ -6,7 +6,6 @@ edition = "2018" license-file = "../../LICENSE" [dependencies] -pairing = "0.15" sha2 = "0.10" hkdf = "0.12.0" ff = "0.5" diff --git a/rust-src/keygen_bls/src/lib.rs b/rust-src/keygen_bls/src/lib.rs index bf56b69ba..292d198ca 100644 --- a/rust-src/keygen_bls/src/lib.rs +++ b/rust-src/keygen_bls/src/lib.rs @@ -1,11 +1,15 @@ //! Generate a private key in a deterministic way from a secret seed and key //! description. -use concordium_base::curve_arithmetic::Curve; -use ff::{Field, PrimeField}; +use concordium_base::{ + curve_arithmetic::{Curve, Field, PrimeField}, + id::constants::{ArCurve, BaseField}, +}; use hkdf::Hkdf; -use pairing::bls12_381::{Fr, FrRepr, G1}; use sha2::{Digest, Sha256}; +type G1 = ArCurve; +type Fr = BaseField; + /// This function is an implementation of the procedure described in /// It computes a random scalar in Fr given a seed (the argument `ikm`). /// @@ -20,11 +24,11 @@ pub fn keygen_bls(ikm: &[u8], key_info: &[u8]) -> Result::zero(); // shift with // 452312848583266388373324160190187140051835877600158453279131187530910662656 = // 2^248 = 2^(31*8) - let shift = Fr::from_repr(FrRepr([0, 0, 0, 72057594037927936])).unwrap(); + let shift = Fr::from_repr(&[0, 0, 0, 72057594037927936]).unwrap(); let mut salt = Sha256::digest(&salt[..]); while sk.is_zero() { let (_, h) = Hkdf::::extract(Some(&salt), &ikm); @@ -70,11 +74,11 @@ pub fn keygen_bls_deprecated(ikm: &[u8], key_info: &[u8]) -> Result::zero(); // shift with // 452312848583266388373324160190187140051835877600158453279131187530910662656 = // 2^248 - let shift = Fr::from_repr(FrRepr([0, 0, 0, 72057594037927936])).unwrap(); + let shift = ::from_repr(&[0, 0, 0, 72057594037927936]).unwrap(); let mut salt = Sha256::digest(&salt[..]); while sk.is_zero() { let (_, h) = Hkdf::::extract(Some(&salt), &ikm); @@ -99,6 +103,7 @@ pub fn keygen_bls_deprecated(ikm: &[u8], key_info: &[u8]) -> Result = BTreeMap::new();