Skip to content

Commit 699f43e

Browse files
authored
p521: implement hash2curve (#964)
1 parent 0b28c07 commit 699f43e

File tree

8 files changed

+434
-39
lines changed

8 files changed

+434
-39
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

clippy.toml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
allow-unwrap-in-tests = true

p256/src/arithmetic/hash2curve.rs

+28-17
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,13 @@ impl OsswuMap for FieldElement {
4848
0x3fff_ffff_c000_0000,
4949
],
5050
c2: FieldElement(U256::from_be_hex(
51-
"a3323851ba997e271ac5d59c3298bf50b2806c63966a1a6653e43951f64fdbe7",
52-
)),
53-
map_a: FieldElement(U256::from_be_hex(
54-
"fffffffc00000004000000000000000000000003fffffffffffffffffffffffc",
51+
"9051d26e12a8f3046913c88f9ea8dfee78400ad7423dcf70a1fd38ee98a195fd",
5552
)),
53+
map_a: FieldElement::from_u64(3).neg(),
5654
map_b: FieldElement(U256::from_be_hex(
5755
"dc30061d04874834e5a220abf7212ed6acf005cd78843090d89cdf6229c4bddf",
5856
)),
59-
z: FieldElement(U256::from_be_hex(
60-
"fffffff50000000b00000000000000000000000afffffffffffffffffffffff5",
61-
)),
57+
z: FieldElement::from_u64(10).neg(),
6258
};
6359
}
6460

@@ -97,20 +93,35 @@ impl FromOkm for Scalar {
9793

9894
#[cfg(test)]
9995
mod tests {
100-
use crate::{FieldElement, NistP256, Scalar, U256};
96+
use crate::{arithmetic::field::MODULUS, FieldElement, NistP256, Scalar, U256};
10197
use elliptic_curve::{
102-
bigint::{ArrayEncoding, NonZero, U384},
98+
bigint::{ArrayEncoding, CheckedSub, NonZero, U384},
10399
consts::U48,
104100
generic_array::GenericArray,
105101
group::cofactor::CofactorGroup,
106-
hash2curve::{self, ExpandMsgXmd, FromOkm, GroupDigest, MapToCurve},
102+
hash2curve::{self, ExpandMsgXmd, FromOkm, GroupDigest, MapToCurve, OsswuMap},
107103
sec1::{self, ToEncodedPoint},
108104
Curve, Field,
109105
};
110106
use hex_literal::hex;
111107
use proptest::{num::u64::ANY, prelude::ProptestConfig, proptest};
112108
use sha2::Sha256;
113109

110+
#[test]
111+
fn params() {
112+
let params = <FieldElement as OsswuMap>::PARAMS;
113+
114+
let c1 = MODULUS.0.checked_sub(&U256::from_u8(3)).unwrap()
115+
/ NonZero::new(U256::from_u8(4)).unwrap();
116+
assert_eq!(
117+
GenericArray::from_iter(params.c1.iter().rev().flat_map(|v| v.to_be_bytes())),
118+
c1.to_be_byte_array()
119+
);
120+
121+
let c2 = FieldElement::from_u64(10).sqrt().unwrap();
122+
assert_eq!(params.c2, c2);
123+
}
124+
114125
#[allow(dead_code)] // TODO(tarcieri): fix commented out code
115126
#[test]
116127
fn hash_to_curve() {
@@ -230,7 +241,7 @@ mod tests {
230241
}
231242
}
232243

233-
/// Taken from <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-16.html#name-oprfp-256-sha-256-2>.
244+
/// Taken from <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-voprf#appendix-A.3>.
234245
#[test]
235246
fn hash_to_scalar_voprf() {
236247
struct TestVector {
@@ -242,22 +253,22 @@ mod tests {
242253

243254
const TEST_VECTORS: &[TestVector] = &[
244255
TestVector {
245-
dst: b"DeriveKeyPairVOPRF10-\x00\x00\x03",
256+
dst: b"DeriveKeyPairOPRFV1-\x00-P256-SHA256",
246257
key_info: b"test key",
247258
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
248-
sk_sm: &hex!("274d7747cf2e26352ecea6bd768c426087da3dfcd466b6841b441ada8412fb33"),
259+
sk_sm: &hex!("159749d750713afe245d2d39ccfaae8381c53ce92d098a9375ee70739c7ac0bf"),
249260
},
250261
TestVector {
251-
dst: b"DeriveKeyPairVOPRF10-\x01\x00\x03",
262+
dst: b"DeriveKeyPairOPRFV1-\x01-P256-SHA256",
252263
key_info: b"test key",
253264
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
254-
sk_sm: &hex!("b3d12edba73e40401fdc27c0094a56337feb3646d1633345af7e7142a6b1559d"),
265+
sk_sm: &hex!("ca5d94c8807817669a51b196c34c1b7f8442fde4334a7121ae4736364312fca6"),
255266
},
256267
TestVector {
257-
dst: b"DeriveKeyPairVOPRF10-\x02\x00\x03",
268+
dst: b"DeriveKeyPairOPRFV1-\x02-P256-SHA256",
258269
key_info: b"test key",
259270
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
260-
sk_sm: &hex!("59519f6c7da344f340ad35ad895a5b97437673cc3ac8b964b823cdb52c932f86"),
271+
sk_sm: &hex!("6ad2173efa689ef2c27772566ad7ff6e2d59b3b196f00219451fb2c89ee4dae2"),
261272
},
262273
];
263274

p384/src/arithmetic/hash2curve.rs

+31-20
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,13 @@ impl OsswuMap for FieldElement {
5151
0x3fff_ffff_ffff_ffff,
5252
],
5353
c2: FieldElement::from_hex(
54-
"019877cc1041b7555743c0ae2e3a3e61fb2aaa2e0e87ea557a563d8b598a0940d0a697a9e0b9e92cfaa314f583c9d066",
55-
),
56-
map_a: FieldElement::from_hex(
57-
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc",
54+
"2accb4a656b0249c71f0500e83da2fdd7f98e383d68b53871f872fcb9ccb80c53c0de1f8a80f7e1914e2ec69f5a626b3",
5855
),
56+
map_a: FieldElement::from_u64(3).neg(),
5957
map_b: FieldElement::from_hex(
6058
"b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
6159
),
62-
z: FieldElement::from_hex(
63-
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffff3",
64-
),
60+
z: FieldElement::from_u64(12).neg(),
6561
};
6662
}
6763

@@ -100,13 +96,13 @@ impl FromOkm for Scalar {
10096

10197
#[cfg(test)]
10298
mod tests {
103-
use crate::{FieldElement, NistP384, Scalar};
99+
use crate::{arithmetic::field::MODULUS, FieldElement, NistP384, Scalar};
104100
use elliptic_curve::{
105-
bigint::{ArrayEncoding, NonZero, U384, U576},
101+
bigint::{ArrayEncoding, CheckedSub, NonZero, U384, U576},
106102
consts::U72,
107103
generic_array::GenericArray,
108104
group::cofactor::CofactorGroup,
109-
hash2curve::{self, ExpandMsgXmd, FromOkm, GroupDigest, MapToCurve},
105+
hash2curve::{self, ExpandMsgXmd, FromOkm, GroupDigest, MapToCurve, OsswuMap},
110106
ops::Reduce,
111107
sec1::{self, ToEncodedPoint},
112108
Curve,
@@ -115,6 +111,21 @@ mod tests {
115111
use proptest::{num::u64::ANY, prelude::ProptestConfig, proptest};
116112
use sha2::Sha384;
117113

114+
#[test]
115+
fn params() {
116+
let params = <FieldElement as OsswuMap>::PARAMS;
117+
118+
let c1 = MODULUS.checked_sub(&U384::from_u8(3)).unwrap()
119+
/ NonZero::new(U384::from_u8(4)).unwrap();
120+
assert_eq!(
121+
GenericArray::from_iter(params.c1.iter().rev().flat_map(|v| v.to_be_bytes())),
122+
c1.to_be_byte_array()
123+
);
124+
125+
let c2 = FieldElement::from_u64(12).sqrt().unwrap();
126+
assert_eq!(params.c2, c2);
127+
}
128+
118129
#[test]
119130
fn hash_to_curve() {
120131
struct TestVector {
@@ -233,7 +244,7 @@ mod tests {
233244
}
234245
}
235246

236-
/// Taken from <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-16.html#name-oprfp-384-sha-384-2>.
247+
/// Taken from <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-voprf#appendix-A.4>.
237248
#[test]
238249
fn hash_to_scalar_voprf() {
239250
struct TestVector {
@@ -245,22 +256,22 @@ mod tests {
245256

246257
const TEST_VECTORS: &[TestVector] = &[
247258
TestVector {
248-
dst: b"DeriveKeyPairVOPRF10-\x00\x00\x04",
259+
dst: b"DeriveKeyPairOPRFV1-\x00-P384-SHA384",
249260
key_info: b"test key",
250-
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
251-
sk_sm: &hex!("c0503759ddd1e31d8c7eae9304c9b1c16f83d1f6d962e3e7b789cd85fd581800e96c5c4256131aafcff9a76919abbd55"),
261+
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
262+
sk_sm: &hex!("dfe7ddc41a4646901184f2b432616c8ba6d452f9bcd0c4f75a5150ef2b2ed02ef40b8b92f60ae591bcabd72a6518f188"),
252263
},
253264
TestVector {
254-
dst: b"DeriveKeyPairVOPRF10-\x01\x00\x04",
265+
dst: b"DeriveKeyPairOPRFV1-\x01-P384-SHA384",
255266
key_info: b"test key",
256-
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
257-
sk_sm: &hex!("514fb6fe2e66af1383840759d56f71730331280f062930ee2a2f7ea42f935acf94087355699d788abfdf09d19a5c85ac"),
267+
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
268+
sk_sm: &hex!("051646b9e6e7a71ae27c1e1d0b87b4381db6d3595eeeb1adb41579adbf992f4278f9016eafc944edaa2b43183581779d"),
258269
},
259270
TestVector {
260-
dst: b"DeriveKeyPairVOPRF10-\x02\x00\x04",
271+
dst: b"DeriveKeyPairOPRFV1-\x02-P384-SHA384",
261272
key_info: b"test key",
262-
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
263-
sk_sm: &hex!("0fcba4a204f67d6c13f780e613915f755319aaa3cb03cd20a5a4a6c403a4812a4fff5d3223e2c309aa66b05cb7611fd4"),
273+
seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
274+
sk_sm: &hex!("5b2690d6954b8fbb159f19935d64133f12770c00b68422559c65431942d721ff79d47d7a75906c30b7818ec0f38b7fb2"),
264275
},
265276
];
266277

p521/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ blobby = "0.3"
3232
ecdsa-core = { version = "0.16", package = "ecdsa", default-features = false, features = ["dev"] }
3333
hex-literal = "0.4"
3434
primeorder = { version = "0.13.3", features = ["dev"], path = "../primeorder" }
35+
proptest = "1.3"
3536
rand_core = { version = "0.6", features = ["getrandom"] }
3637

3738
[features]
@@ -44,6 +45,7 @@ digest = ["ecdsa-core/digest", "ecdsa-core/hazmat"]
4445
ecdh = ["arithmetic", "elliptic-curve/ecdh"]
4546
ecdsa = ["arithmetic", "ecdsa-core/signing", "ecdsa-core/verifying", "sha512"]
4647
getrandom = ["rand_core/getrandom"]
48+
hash2curve = ["arithmetic", "elliptic-curve/hash2curve"]
4749
jwk = ["elliptic-curve/jwk"]
4850
pem = ["elliptic-curve/pem", "pkcs8"]
4951
pkcs8 = ["ecdsa-core?/pkcs8", "elliptic-curve/pkcs8"]

p521/src/arithmetic.rs

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
//! [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final
66
77
pub(crate) mod field;
8+
#[cfg(feature = "hash2curve")]
9+
mod hash2curve;
810
pub(crate) mod scalar;
911
mod util;
1012

p521/src/arithmetic/field.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ use super::util::u576_to_le_bytes;
4949
/// p = 2^{521} − 1
5050
const MODULUS_HEX: &str = "00000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
5151

52-
const MODULUS: U576 = U576::from_be_hex(MODULUS_HEX);
52+
pub(crate) const MODULUS: U576 = U576::from_be_hex(MODULUS_HEX);
5353

5454
/// Element of the secp521r1 base field used for curve coordinates.
5555
#[derive(Clone, Copy)]
56-
pub struct FieldElement(fiat_p521_tight_field_element);
56+
pub struct FieldElement(pub(crate) fiat_p521_tight_field_element);
5757

5858
impl FieldElement {
5959
/// Zero element.

0 commit comments

Comments
 (0)