From 2edc4f6e8e4015dfd1d6b313782f72d9aa5a05fa Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Wed, 7 Dec 2022 15:51:39 -0300 Subject: [PATCH 1/4] add check for canonical point encodings where needed, and tests --- frost-ed25519/Cargo.toml | 1 + frost-ed25519/src/lib.rs | 9 +++++++++ frost-ed25519/tests/frost.rs | 11 +++++++++++ frost-ed448/Cargo.toml | 1 + frost-ed448/src/lib.rs | 11 +++++++++-- frost-ed448/tests/frost.rs | 31 +++++++++++++++++++++++++++++++ frost-p256/Cargo.toml | 1 + frost-p256/tests/frost.rs | 26 ++++++++++++++++++++++++++ frost-secp256k1/Cargo.toml | 1 + frost-secp256k1/tests/frost.rs | 26 ++++++++++++++++++++++++++ 10 files changed, 116 insertions(+), 2 deletions(-) diff --git a/frost-ed25519/Cargo.toml b/frost-ed25519/Cargo.toml index ccc73022..9e952d94 100644 --- a/frost-ed25519/Cargo.toml +++ b/frost-ed25519/Cargo.toml @@ -33,6 +33,7 @@ bincode = "1" criterion = "0.4" ed25519-dalek = "1.0.1" ed25519-zebra = "3.0.0" +hex = "0.4.3" lazy_static = "1.4" proptest = "1.0" proptest-derive = "0.3" diff --git a/frost-ed25519/src/lib.rs b/frost-ed25519/src/lib.rs index d1ebb465..b9775fb7 100644 --- a/frost-ed25519/src/lib.rs +++ b/frost-ed25519/src/lib.rs @@ -54,6 +54,15 @@ impl Group for Ed25519Group { if point == Self::identity() { Err(Error::InvalidIdentityElement) } else if point.is_torsion_free() { + // At this point we should reject points which were not + // encoded canonically (i.e. Y coordinate >= p). + // However, we don't allow non-prime order elements, + // and that suffices to also reject non-canonical encodings + // per https://eprint.iacr.org/2020/1244.pdf: + // + // > There are 19 elliptic curve points that can be encoded in a non-canonical form. + // > (...) Among these points there are 2 points of small order and from the + // > remaining 17 y-coordinates only 10 decode to valid curve points all of mixed order. Ok(point) } else { Err(Error::InvalidNonPrimeOrderElement) diff --git a/frost-ed25519/tests/frost.rs b/frost-ed25519/tests/frost.rs index f14d329d..29734a85 100644 --- a/frost-ed25519/tests/frost.rs +++ b/frost-ed25519/tests/frost.rs @@ -38,3 +38,14 @@ fn check_deserialize_identity() { let r = <::Group as Group>::deserialize(&encoded_identity); assert_eq!(r, Err(Error::InvalidIdentityElement)); } + +#[test] +fn check_deserialize_non_prime_order() { + let encoded_point = + hex::decode("0300000000000000000000000000000000000000000000000000000000000000") + .unwrap() + .try_into() + .unwrap(); + let r = <::Group as Group>::deserialize(&encoded_point); + assert_eq!(r, Err(Error::InvalidNonPrimeOrderElement)); +} diff --git a/frost-ed448/Cargo.toml b/frost-ed448/Cargo.toml index 9e282ebe..aea64f42 100644 --- a/frost-ed448/Cargo.toml +++ b/frost-ed448/Cargo.toml @@ -32,6 +32,7 @@ sha3 = "0.10.6" bincode = "1" criterion = "0.4" lazy_static = "1.4" +hex = "0.4.3" proptest = "1.0" proptest-derive = "0.3" rand = "0.8" diff --git a/frost-ed448/src/lib.rs b/frost-ed448/src/lib.rs index c686af37..52337b4d 100644 --- a/frost-ed448/src/lib.rs +++ b/frost-ed448/src/lib.rs @@ -93,12 +93,19 @@ impl Group for Ed448Group { } fn deserialize(buf: &Self::Serialization) -> Result { - match CompressedEdwardsY(*buf).decompress() { + let compressed = CompressedEdwardsY(*buf); + match compressed.decompress() { Some(point) => { if point == Self::identity() { Err(Error::InvalidIdentityElement) } else if point.is_torsion_free() { - Ok(point) + // decompress() does not check for canonicality, so we + // check by recompressing and comparing + if point.compress().0 != compressed.0 { + Err(Error::MalformedElement) + } else { + Ok(point) + } } else { Err(Error::InvalidNonPrimeOrderElement) } diff --git a/frost-ed448/tests/frost.rs b/frost-ed448/tests/frost.rs index 06e22a53..029c3a8d 100644 --- a/frost-ed448/tests/frost.rs +++ b/frost-ed448/tests/frost.rs @@ -42,3 +42,34 @@ fn check_deserialize_identity() { let r = <::Group as Group>::deserialize(&encoded_identity); assert_eq!(r, Err(Error::InvalidIdentityElement)); } + +#[test] +fn check_deserialize_non_canonical() { + let mut encoded_generator = ExtendedPoint::generator().compress().0; + + let r = <::Group as Group>::deserialize(&encoded_generator); + assert!(r.is_ok()); + + // The last byte only should have the sign bit. Set all other bits to + // create a non-canonical encoding. + encoded_generator[56] |= 0x7f; + let r = <::Group as Group>::deserialize(&encoded_generator); + assert_eq!(r, Err(Error::MalformedElement)); + + // Besides the last byte, it is still possible to get non-canonical encodings. + // This is y = p + 19 which is non-canonical and maps to a valid prime-order point. + let encoded_point = hex::decode("12000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00").unwrap().try_into().unwrap(); + let r = <::Group as Group>::deserialize(&encoded_point); + assert_eq!(r, Err(Error::MalformedElement)); +} + +#[test] +fn check_deserialize_non_prime_order() { + let encoded_point = + hex::decode("030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + .unwrap() + .try_into() + .unwrap(); + let r = <::Group as Group>::deserialize(&encoded_point); + assert_eq!(r, Err(Error::InvalidNonPrimeOrderElement)); +} diff --git a/frost-p256/Cargo.toml b/frost-p256/Cargo.toml index a62f6ff3..2dc907df 100644 --- a/frost-p256/Cargo.toml +++ b/frost-p256/Cargo.toml @@ -32,6 +32,7 @@ bincode = "1" criterion = "0.4" ed25519-dalek = "1.0.1" ed25519-zebra = "3.0.0" +hex = "0.4.3" lazy_static = "1.4" proptest = "1.0" proptest-derive = "0.3" diff --git a/frost-p256/tests/frost.rs b/frost-p256/tests/frost.rs index 6097bc15..1e68db8c 100644 --- a/frost-p256/tests/frost.rs +++ b/frost-p256/tests/frost.rs @@ -39,3 +39,29 @@ fn check_deserialize_identity() { let r = <::Group as Group>::deserialize(&encoded_identity); assert_eq!(r, Err(Error::MalformedElement)); } + +#[test] +fn check_deserialize_non_canonical() { + let mut encoded_generator = <::Group as Group>::serialize( + &<::Group as Group>::generator(), + ); + + let r = <::Group as Group>::deserialize(&encoded_generator); + assert!(r.is_ok()); + + // The first byte should be 0x02 or 0x03. Set other value to + // create a non-canonical encoding. + encoded_generator[0] = 0xFF; + let r = <::Group as Group>::deserialize(&encoded_generator); + assert_eq!(r, Err(Error::MalformedElement)); + + // Besides the first byte, it is still possible to get non-canonical encodings. + // This is x = p + 5 which is non-canonical and maps to a valid prime-order point. + let encoded_point = + hex::decode("02ffffffff00000001000000000000000000000001000000000000000000000004") + .unwrap() + .try_into() + .unwrap(); + let r = <::Group as Group>::deserialize(&encoded_point); + assert_eq!(r, Err(Error::MalformedElement)); +} diff --git a/frost-secp256k1/Cargo.toml b/frost-secp256k1/Cargo.toml index 5bb98a45..35338e5c 100644 --- a/frost-secp256k1/Cargo.toml +++ b/frost-secp256k1/Cargo.toml @@ -32,6 +32,7 @@ bincode = "1" criterion = "0.4" ed25519-dalek = "1.0.1" ed25519-zebra = "3.0.0" +hex = "0.4.3" lazy_static = "1.4" proptest = "1.0" proptest-derive = "0.3" diff --git a/frost-secp256k1/tests/frost.rs b/frost-secp256k1/tests/frost.rs index 4af0c999..5677867c 100644 --- a/frost-secp256k1/tests/frost.rs +++ b/frost-secp256k1/tests/frost.rs @@ -39,3 +39,29 @@ fn check_deserialize_identity() { let r = <::Group as Group>::deserialize(&encoded_identity); assert_eq!(r, Err(Error::MalformedElement)); } + +#[test] +fn check_deserialize_non_canonical() { + let mut encoded_generator = <::Group as Group>::serialize( + &<::Group as Group>::generator(), + ); + + let r = <::Group as Group>::deserialize(&encoded_generator); + assert!(r.is_ok()); + + // The first byte should be 0x02 or 0x03. Set other value to + // create a non-canonical encoding. + encoded_generator[0] = 0xFF; + let r = <::Group as Group>::deserialize(&encoded_generator); + assert_eq!(r, Err(Error::MalformedElement)); + + // Besides the first byte, it is still possible to get non-canonical encodings. + // This is x = p + 2 which is non-canonical and maps to a valid prime-order point. + let encoded_point = + hex::decode("02fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc31") + .unwrap() + .try_into() + .unwrap(); + let r = <::Group as Group>::deserialize(&encoded_point); + assert_eq!(r, Err(Error::MalformedElement)); +} From bbf7555437acdec4427acc736a6c0331ee730f6e Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Fri, 9 Dec 2022 16:24:13 -0300 Subject: [PATCH 2/4] remove unneeded 'as' keywords --- frost-ed25519/tests/frost.rs | 4 ++-- frost-ed448/tests/frost.rs | 10 +++++----- frost-p256/tests/frost.rs | 12 ++++++------ frost-ristretto255/tests/frost.rs | 2 +- frost-secp256k1/tests/frost.rs | 12 ++++++------ 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/frost-ed25519/tests/frost.rs b/frost-ed25519/tests/frost.rs index 29734a85..ac1fb812 100644 --- a/frost-ed25519/tests/frost.rs +++ b/frost-ed25519/tests/frost.rs @@ -35,7 +35,7 @@ fn check_bad_batch_verify() { fn check_deserialize_identity() { let encoded_identity = EdwardsPoint::identity().compress().to_bytes(); - let r = <::Group as Group>::deserialize(&encoded_identity); + let r = ::Group::deserialize(&encoded_identity); assert_eq!(r, Err(Error::InvalidIdentityElement)); } @@ -46,6 +46,6 @@ fn check_deserialize_non_prime_order() { .unwrap() .try_into() .unwrap(); - let r = <::Group as Group>::deserialize(&encoded_point); + let r = ::Group::deserialize(&encoded_point); assert_eq!(r, Err(Error::InvalidNonPrimeOrderElement)); } diff --git a/frost-ed448/tests/frost.rs b/frost-ed448/tests/frost.rs index 029c3a8d..60eecc71 100644 --- a/frost-ed448/tests/frost.rs +++ b/frost-ed448/tests/frost.rs @@ -39,7 +39,7 @@ fn check_bad_batch_verify() { fn check_deserialize_identity() { let encoded_identity = ExtendedPoint::identity().compress().0; - let r = <::Group as Group>::deserialize(&encoded_identity); + let r = ::Group::deserialize(&encoded_identity); assert_eq!(r, Err(Error::InvalidIdentityElement)); } @@ -47,19 +47,19 @@ fn check_deserialize_identity() { fn check_deserialize_non_canonical() { let mut encoded_generator = ExtendedPoint::generator().compress().0; - let r = <::Group as Group>::deserialize(&encoded_generator); + let r = ::Group::deserialize(&encoded_generator); assert!(r.is_ok()); // The last byte only should have the sign bit. Set all other bits to // create a non-canonical encoding. encoded_generator[56] |= 0x7f; - let r = <::Group as Group>::deserialize(&encoded_generator); + let r = ::Group::deserialize(&encoded_generator); assert_eq!(r, Err(Error::MalformedElement)); // Besides the last byte, it is still possible to get non-canonical encodings. // This is y = p + 19 which is non-canonical and maps to a valid prime-order point. let encoded_point = hex::decode("12000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00").unwrap().try_into().unwrap(); - let r = <::Group as Group>::deserialize(&encoded_point); + let r = ::Group::deserialize(&encoded_point); assert_eq!(r, Err(Error::MalformedElement)); } @@ -70,6 +70,6 @@ fn check_deserialize_non_prime_order() { .unwrap() .try_into() .unwrap(); - let r = <::Group as Group>::deserialize(&encoded_point); + let r = ::Group::deserialize(&encoded_point); assert_eq!(r, Err(Error::InvalidNonPrimeOrderElement)); } diff --git a/frost-p256/tests/frost.rs b/frost-p256/tests/frost.rs index 1e68db8c..37e54e02 100644 --- a/frost-p256/tests/frost.rs +++ b/frost-p256/tests/frost.rs @@ -36,23 +36,23 @@ fn check_deserialize_identity() { // allow us to change that. Try to send something similar. let encoded_identity = [0u8; 33]; - let r = <::Group as Group>::deserialize(&encoded_identity); + let r = ::Group::deserialize(&encoded_identity); assert_eq!(r, Err(Error::MalformedElement)); } #[test] fn check_deserialize_non_canonical() { - let mut encoded_generator = <::Group as Group>::serialize( - &<::Group as Group>::generator(), + let mut encoded_generator = ::Group::serialize( + &::Group::generator(), ); - let r = <::Group as Group>::deserialize(&encoded_generator); + let r = ::Group::deserialize(&encoded_generator); assert!(r.is_ok()); // The first byte should be 0x02 or 0x03. Set other value to // create a non-canonical encoding. encoded_generator[0] = 0xFF; - let r = <::Group as Group>::deserialize(&encoded_generator); + let r = ::Group::deserialize(&encoded_generator); assert_eq!(r, Err(Error::MalformedElement)); // Besides the first byte, it is still possible to get non-canonical encodings. @@ -62,6 +62,6 @@ fn check_deserialize_non_canonical() { .unwrap() .try_into() .unwrap(); - let r = <::Group as Group>::deserialize(&encoded_point); + let r = ::Group::deserialize(&encoded_point); assert_eq!(r, Err(Error::MalformedElement)); } diff --git a/frost-ristretto255/tests/frost.rs b/frost-ristretto255/tests/frost.rs index 9dc832f2..e88dde84 100644 --- a/frost-ristretto255/tests/frost.rs +++ b/frost-ristretto255/tests/frost.rs @@ -35,6 +35,6 @@ fn check_bad_batch_verify() { fn check_deserialize_identity() { let encoded_identity = RistrettoPoint::identity().compress().to_bytes(); - let r = <::Group as Group>::deserialize(&encoded_identity); + let r = ::Group::deserialize(&encoded_identity); assert_eq!(r, Err(Error::InvalidIdentityElement)); } diff --git a/frost-secp256k1/tests/frost.rs b/frost-secp256k1/tests/frost.rs index 5677867c..91ce6311 100644 --- a/frost-secp256k1/tests/frost.rs +++ b/frost-secp256k1/tests/frost.rs @@ -36,23 +36,23 @@ fn check_deserialize_identity() { // allow us to change that. Try to send something similar. let encoded_identity = [0u8; 33]; - let r = <::Group as Group>::deserialize(&encoded_identity); + let r = ::Group::deserialize(&encoded_identity); assert_eq!(r, Err(Error::MalformedElement)); } #[test] fn check_deserialize_non_canonical() { - let mut encoded_generator = <::Group as Group>::serialize( - &<::Group as Group>::generator(), + let mut encoded_generator = ::Group::serialize( + &::Group::generator(), ); - let r = <::Group as Group>::deserialize(&encoded_generator); + let r = ::Group::deserialize(&encoded_generator); assert!(r.is_ok()); // The first byte should be 0x02 or 0x03. Set other value to // create a non-canonical encoding. encoded_generator[0] = 0xFF; - let r = <::Group as Group>::deserialize(&encoded_generator); + let r = ::Group::deserialize(&encoded_generator); assert_eq!(r, Err(Error::MalformedElement)); // Besides the first byte, it is still possible to get non-canonical encodings. @@ -62,6 +62,6 @@ fn check_deserialize_non_canonical() { .unwrap() .try_into() .unwrap(); - let r = <::Group as Group>::deserialize(&encoded_point); + let r = ::Group::deserialize(&encoded_point); assert_eq!(r, Err(Error::MalformedElement)); } From 8b3e3b1b313404185c4cbb80b77356d7e51b9ecd Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Wed, 14 Dec 2022 11:31:42 -0300 Subject: [PATCH 3/4] fix after syncing with main --- frost-ed25519/tests/frost.rs | 4 ++-- frost-ed448/src/lib.rs | 4 ++-- frost-ed448/tests/frost.rs | 8 ++++---- frost-p256/tests/frost.rs | 6 +++--- frost-ristretto255/tests/frost.rs | 2 +- frost-secp256k1/tests/frost.rs | 6 +++--- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frost-ed25519/tests/frost.rs b/frost-ed25519/tests/frost.rs index c05b72da..d57b9873 100644 --- a/frost-ed25519/tests/frost.rs +++ b/frost-ed25519/tests/frost.rs @@ -36,7 +36,7 @@ fn check_deserialize_identity() { let encoded_identity = EdwardsPoint::identity().compress().to_bytes(); let r = ::Group::deserialize(&encoded_identity); - assert_eq!(r, Err(Error::InvalidIdentityElement)); + assert_eq!(r, Err(GroupError::InvalidIdentityElement)); } #[test] @@ -47,5 +47,5 @@ fn check_deserialize_non_prime_order() { .try_into() .unwrap(); let r = ::Group::deserialize(&encoded_point); - assert_eq!(r, Err(Error::InvalidNonPrimeOrderElement)); + assert_eq!(r, Err(GroupError::InvalidNonPrimeOrderElement)); } diff --git a/frost-ed448/src/lib.rs b/frost-ed448/src/lib.rs index 50a28f49..3916a5ed 100644 --- a/frost-ed448/src/lib.rs +++ b/frost-ed448/src/lib.rs @@ -93,7 +93,7 @@ impl Group for Ed448Group { element.compress().0 } - fn deserialize(buf: &Self::Serialization) -> Result { + fn deserialize(buf: &Self::Serialization) -> Result { let compressed = CompressedEdwardsY(*buf); match compressed.decompress() { Some(point) => { @@ -103,7 +103,7 @@ impl Group for Ed448Group { // decompress() does not check for canonicality, so we // check by recompressing and comparing if point.compress().0 != compressed.0 { - Err(Error::MalformedElement) + Err(GroupError::MalformedElement) } else { Ok(point) } diff --git a/frost-ed448/tests/frost.rs b/frost-ed448/tests/frost.rs index 67800dbb..5420ca29 100644 --- a/frost-ed448/tests/frost.rs +++ b/frost-ed448/tests/frost.rs @@ -40,7 +40,7 @@ fn check_deserialize_identity() { let encoded_identity = ExtendedPoint::identity().compress().0; let r = ::Group::deserialize(&encoded_identity); - assert_eq!(r, Err(Error::InvalidIdentityElement)); + assert_eq!(r, Err(GroupError::InvalidIdentityElement)); } #[test] @@ -54,13 +54,13 @@ fn check_deserialize_non_canonical() { // create a non-canonical encoding. encoded_generator[56] |= 0x7f; let r = ::Group::deserialize(&encoded_generator); - assert_eq!(r, Err(Error::MalformedElement)); + assert_eq!(r, Err(GroupError::MalformedElement)); // Besides the last byte, it is still possible to get non-canonical encodings. // This is y = p + 19 which is non-canonical and maps to a valid prime-order point. let encoded_point = hex::decode("12000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00").unwrap().try_into().unwrap(); let r = ::Group::deserialize(&encoded_point); - assert_eq!(r, Err(Error::MalformedElement)); + assert_eq!(r, Err(GroupError::MalformedElement)); } #[test] @@ -71,5 +71,5 @@ fn check_deserialize_non_prime_order() { .try_into() .unwrap(); let r = ::Group::deserialize(&encoded_point); - assert_eq!(r, Err(Error::InvalidNonPrimeOrderElement)); + assert_eq!(r, Err(GroupError::InvalidNonPrimeOrderElement)); } diff --git a/frost-p256/tests/frost.rs b/frost-p256/tests/frost.rs index 161b09cb..6bda8897 100644 --- a/frost-p256/tests/frost.rs +++ b/frost-p256/tests/frost.rs @@ -37,7 +37,7 @@ fn check_deserialize_identity() { let encoded_identity = [0u8; 33]; let r = ::Group::deserialize(&encoded_identity); - assert_eq!(r, Err(Error::MalformedElement)); + assert_eq!(r, Err(GroupError::MalformedElement)); } #[test] @@ -53,7 +53,7 @@ fn check_deserialize_non_canonical() { // create a non-canonical encoding. encoded_generator[0] = 0xFF; let r = ::Group::deserialize(&encoded_generator); - assert_eq!(r, Err(Error::MalformedElement)); + assert_eq!(r, Err(GroupError::MalformedElement)); // Besides the first byte, it is still possible to get non-canonical encodings. // This is x = p + 5 which is non-canonical and maps to a valid prime-order point. @@ -63,5 +63,5 @@ fn check_deserialize_non_canonical() { .try_into() .unwrap(); let r = ::Group::deserialize(&encoded_point); - assert_eq!(r, Err(Error::MalformedElement)); + assert_eq!(r, Err(GroupError::MalformedElement)); } diff --git a/frost-ristretto255/tests/frost.rs b/frost-ristretto255/tests/frost.rs index fb10bd67..c20f266c 100644 --- a/frost-ristretto255/tests/frost.rs +++ b/frost-ristretto255/tests/frost.rs @@ -36,5 +36,5 @@ fn check_deserialize_identity() { let encoded_identity = RistrettoPoint::identity().compress().to_bytes(); let r = ::Group::deserialize(&encoded_identity); - assert_eq!(r, Err(Error::InvalidIdentityElement)); + assert_eq!(r, Err(GroupError::InvalidIdentityElement)); } diff --git a/frost-secp256k1/tests/frost.rs b/frost-secp256k1/tests/frost.rs index 98c1bbbc..67ca00e2 100644 --- a/frost-secp256k1/tests/frost.rs +++ b/frost-secp256k1/tests/frost.rs @@ -37,7 +37,7 @@ fn check_deserialize_identity() { let encoded_identity = [0u8; 33]; let r = ::Group::deserialize(&encoded_identity); - assert_eq!(r, Err(Error::MalformedElement)); + assert_eq!(r, Err(GroupError::MalformedElement)); } #[test] @@ -53,7 +53,7 @@ fn check_deserialize_non_canonical() { // create a non-canonical encoding. encoded_generator[0] = 0xFF; let r = ::Group::deserialize(&encoded_generator); - assert_eq!(r, Err(Error::MalformedElement)); + assert_eq!(r, Err(GroupError::MalformedElement)); // Besides the first byte, it is still possible to get non-canonical encodings. // This is x = p + 2 which is non-canonical and maps to a valid prime-order point. @@ -63,5 +63,5 @@ fn check_deserialize_non_canonical() { .try_into() .unwrap(); let r = ::Group::deserialize(&encoded_point); - assert_eq!(r, Err(Error::MalformedElement)); + assert_eq!(r, Err(GroupError::MalformedElement)); } From aaa4264f80fb81b6c1190a0bb02f274b1ff9aff7 Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Wed, 14 Dec 2022 14:17:14 -0300 Subject: [PATCH 4/4] pin curve25519-dalek for now due to breaking changes --- frost-core/Cargo.toml | 2 +- frost-ed25519/Cargo.toml | 2 +- frost-ristretto255/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frost-core/Cargo.toml b/frost-core/Cargo.toml index ee627785..16947a1e 100644 --- a/frost-core/Cargo.toml +++ b/frost-core/Cargo.toml @@ -31,7 +31,7 @@ proptest-derive = { version = "0.3", optional = true } serde_json = { version = "1.0", optional = true } [dev-dependencies] -curve25519-dalek = { version = "4.0.0-pre.1", features = ["serde"] } +curve25519-dalek = { version = "=4.0.0-pre.1", features = ["serde"] } lazy_static = "1.4" proptest = "1.0" rand = "0.8" diff --git a/frost-ed25519/Cargo.toml b/frost-ed25519/Cargo.toml index 9e952d94..636badfc 100644 --- a/frost-ed25519/Cargo.toml +++ b/frost-ed25519/Cargo.toml @@ -22,7 +22,7 @@ description = "A Schnorr signature scheme over the prime-order Ristretto group t features = ["nightly"] [dependencies] -curve25519-dalek = { version = "4.0.0-pre.1", features = ["serde"] } +curve25519-dalek = { version = "=4.0.0-pre.1", features = ["serde"] } frost-core = { path = "../frost-core", features = ["test-impl"] } frost-ristretto255 = { path = "../frost-ristretto255" } rand_core = "0.6" diff --git a/frost-ristretto255/Cargo.toml b/frost-ristretto255/Cargo.toml index 34f95979..f195e431 100644 --- a/frost-ristretto255/Cargo.toml +++ b/frost-ristretto255/Cargo.toml @@ -18,7 +18,7 @@ description = "A Schnorr signature scheme over the prime-order Ristretto group t features = ["nightly"] [dependencies] -curve25519-dalek = { version = "4.0.0-pre.1", features = ["serde"] } +curve25519-dalek = { version = "=4.0.0-pre.1", features = ["serde"] } frost-core = { path = "../frost-core", features = ["test-impl"] } rand_core = "0.6" sha2 = "0.10.2"