1 use std::cmp; 2 use std::convert::{TryFrom, TryInto}; 3 use std::fmt; 4 use std::time::{SystemTime, Duration as SystemDuration, UNIX_EPOCH}; 5 use std::u32; 6 7 #[cfg(any(test, feature = "quickcheck"))] 8 use quickcheck::{Arbitrary, Gen}; 9 10 use crate::{ 11 Error, 12 Result, 13 }; 14 15 /// A timestamp representable by OpenPGP. 16 /// 17 /// OpenPGP timestamps are represented as `u32` containing the number of seconds 18 /// elapsed since midnight, 1 January 1970 UTC ([Section 3.5 of RFC 4880]). 19 /// 20 /// They cannot express dates further than 7th February of 2106 or earlier than 21 /// the [UNIX epoch]. Unlike Unix's `time_t`, OpenPGP's timestamp is unsigned so 22 /// it rollsover in 2106, not 2038. 23 /// 24 /// # Examples 25 /// 26 /// Signature creation time is internally stored as a `Timestamp`: 27 /// 28 /// Note that this example retrieves raw packet value. 29 /// Use [`SubpacketArea::signature_creation_time`] to get the signature creation time. 30 /// 31 /// [`SubpacketArea::signature_creation_time`]: ../packet/signature/subpacket/struct.SubpacketArea.html#method.signature_creation_time 32 /// 33 /// ``` 34 /// use sequoia_openpgp as openpgp; 35 /// # use openpgp::Result; 36 /// use std::convert::From; 37 /// use std::time::SystemTime; 38 /// use openpgp::cert::prelude::*; 39 /// use openpgp::policy::StandardPolicy; 40 /// use openpgp::packet::signature::subpacket::{SubpacketTag, SubpacketValue}; 41 /// 42 /// # fn main() -> Result<()> { 43 /// let (cert, _) = 44 /// CertBuilder::general_purpose(None, Some("alice@example.org")) 45 /// .generate()?; 46 /// 47 /// let subkey = cert.keys().subkeys().next().unwrap(); 48 /// let packets = subkey.bundle().self_signatures()[0].hashed_area(); 49 /// 50 /// match packets.subpacket(SubpacketTag::SignatureCreationTime).unwrap().value() { 51 /// SubpacketValue::SignatureCreationTime(ts) => assert!(u32::from(*ts) > 0), 52 /// v => panic!("Unexpected subpacket: {:?}", v), 53 /// } 54 /// 55 /// let p = &StandardPolicy::new(); 56 /// let now = SystemTime::now(); 57 /// assert!(subkey.binding_signature(p, now)?.signature_creation_time().is_some()); 58 /// # Ok(()) } 59 /// ``` 60 /// 61 /// [Section 3.5 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-3.5 62 /// [UNIX epoch]: https://en.wikipedia.org/wiki/Unix_time 63 /// [`Timestamp::round_down`]: ../types/struct.Timestamp.html#method.round_down 64 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 65 pub struct Timestamp(u32); 66 67 impl From<Timestamp> for u32 { 68 fn from(t: Timestamp) -> Self { 69 t.0 70 } 71 } 72 73 impl From<u32> for Timestamp { 74 fn from(t: u32) -> Self { 75 Timestamp(t) 76 } 77 } 78 79 impl TryFrom<SystemTime> for Timestamp { 80 type Error = anyhow::Error; 81 82 fn try_from(t: SystemTime) -> Result<Self> { 83 match t.duration_since(std::time::UNIX_EPOCH) { 84 Ok(d) if d.as_secs() <= std::u32::MAX as u64 => 85 Ok(Timestamp(d.as_secs() as u32)), 86 _ => Err(Error::InvalidArgument( 87 format!("Time exceeds u32 epoch: {:?}", t)) 88 .into()), 89 } 90 } 91 } 92 93 impl From<Timestamp> for SystemTime { 94 fn from(t: Timestamp) -> Self { 95 UNIX_EPOCH + SystemDuration::new(t.0 as u64, 0) 96 } 97 } 98 99 impl From<Timestamp> for Option<SystemTime> { 100 fn from(t: Timestamp) -> Self { 101 Some(t.into()) 102 } 103 } 104 105 impl fmt::Display for Timestamp { 106 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 107 write!(f, "{}", crate::fmt::time(&SystemTime::from(*self))) 108 } 109 } 110 111 impl fmt::Debug for Timestamp { 112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 113 write!(f, "{}", self.0) 114 } 115 } 116 117 impl Timestamp { 118 /// Returns the current time. 119 pub fn now() -> Timestamp { 120 SystemTime::now().try_into() 121 .expect("representable for the next hundred years") 122 } 123 124 /// Adds a duration to this timestamp. 125 /// 126 /// Returns `None` if the resulting timestamp is not 127 /// representable. 128 pub fn checked_add(&self, d: Duration) -> Option<Timestamp> { 129 self.0.checked_add(d.0).map(|v| Self(v)) 130 } 131 132 /// Subtracts a duration from this timestamp. 133 /// 134 /// Returns `None` if the resulting timestamp is not 135 /// representable. 136 pub fn checked_sub(&self, d: Duration) -> Option<Timestamp> { 137 self.0.checked_sub(d.0).map(|v| Self(v)) 138 } 139 140 /// Rounds down to the given level of precision. 141 /// 142 /// This can be used to reduce the metadata leak resulting from 143 /// time stamps. For example, a group of people attending a key 144 /// signing event could be identified by comparing the time stamps 145 /// of resulting certifications. By rounding the creation time of 146 /// these signatures down, all of them, and others, fall into the 147 /// same bucket. 148 /// 149 /// The given level `p` determines the resulting resolution of 150 /// `2^p` seconds. The default is `21`, which results in a 151 /// resolution of 24 days, or roughly a month. `p` must be lower 152 /// than 32. 153 /// 154 /// The lower limit `floor` represents the earliest time the timestamp will be 155 /// rounded down to. 156 /// 157 /// See also [`Duration::round_up`](struct.Duration.html#method.round_up). 158 /// 159 /// # Important note 160 /// 161 /// If we create a signature, it is important that the signature's 162 /// creation time does not predate the signing keys creation time, 163 /// or otherwise violate the key's validity constraints. 164 /// This can be achieved by using the `floor` parameter. 165 /// 166 /// To ensure validity, use this function to round the time down, 167 /// using the latest known relevant timestamp as a floor. 168 /// Then, lookup all keys and other objects like userids using this 169 /// timestamp, and on success create the signature: 170 /// 171 /// ```rust 172 /// # use sequoia_openpgp::{*, packet::prelude::*, types::*, cert::*}; 173 /// use sequoia_openpgp::policy::StandardPolicy; 174 /// 175 /// # f().unwrap(); 176 /// # fn f() -> Result<()> { 177 /// let policy = &StandardPolicy::new(); 178 /// 179 /// // Let's fix a time. 180 /// let now = Timestamp::from(1583436160); 181 /// 182 /// let cert_creation_alice = now.checked_sub(Duration::weeks(2)?).unwrap(); 183 /// let cert_creation_bob = now.checked_sub(Duration::weeks(1)?).unwrap(); 184 /// 185 /// // Generate a Cert for Alice. 186 /// let (alice, _) = CertBuilder::new() 187 /// .set_creation_time(cert_creation_alice) 188 /// .set_primary_key_flags(KeyFlags::empty().set_certification()) 189 /// .add_userid("alice@example.org") 190 /// .generate()?; 191 /// 192 /// // Generate a Cert for Bob. 193 /// let (bob, _) = CertBuilder::new() 194 /// .set_creation_time(cert_creation_bob) 195 /// .set_primary_key_flags(KeyFlags::empty().set_certification()) 196 /// .add_userid("bob@example.org") 197 /// .generate()?; 198 /// 199 /// let sign_with_p = |p| -> Result<Signature> { 200 /// // Round `now` down, then use `t` for all lookups. 201 /// // Use the creation time of Bob's Cert as lower bound for rounding. 202 /// let t: std::time::SystemTime = now.round_down(p, cert_creation_bob)?.into(); 203 /// 204 /// // First, get the certification key. 205 /// let mut keypair = 206 /// alice.keys().with_policy(policy, t).secret().for_certification() 207 /// .nth(0).ok_or_else(|| anyhow::anyhow!("no valid key at"))? 208 /// .key().clone().into_keypair()?; 209 /// 210 /// // Then, lookup the binding between `bob@example.org` and 211 /// // `bob` at `t`. 212 /// let ca = bob.userids().with_policy(policy, t) 213 /// .filter(|ca| ca.userid().value() == b"bob@example.org") 214 /// .nth(0).ok_or_else(|| anyhow::anyhow!("no valid userid"))?; 215 /// 216 /// // Finally, Alice certifies the binding between 217 /// // `bob@example.org` and `bob` at `t`. 218 /// ca.userid().certify(&mut keypair, &bob, 219 /// SignatureType::PositiveCertification, None, t) 220 /// }; 221 /// 222 /// assert!(sign_with_p(21).is_ok()); 223 /// assert!(sign_with_p(22).is_ok()); // Rounded to bob's cert's creation time. 224 /// assert!(sign_with_p(32).is_err()); // Invalid precision 225 /// # Ok(()) } 226 /// ``` 227 pub fn round_down<P, F>(&self, precision: P, floor: F) -> Result<Timestamp> 228 where P: Into<Option<u8>>, 229 F: Into<Option<SystemTime>> 230 { 231 let p = precision.into().unwrap_or(21) as u32; 232 if p < 32 { 233 let rounded = Self(self.0 & !((1 << p) - 1)); 234 match floor.into() { 235 Some(floor) => { 236 Ok(cmp::max(rounded, floor.try_into()?)) 237 } 238 None => { Ok(rounded) } 239 } 240 } else { 241 Err(Error::InvalidArgument( 242 format!("Invalid precision {}", p)).into()) 243 } 244 } 245 } 246 247 #[cfg(any(test, feature = "quickcheck"))] 248 impl Arbitrary for Timestamp { 249 fn arbitrary<G: Gen>(g: &mut G) -> Self { 250 Timestamp(u32::arbitrary(g)) 251 } 252 } 253 254 /// A duration representable by OpenPGP. 255 /// 256 /// # Examples 257 /// 258 /// ``` 259 /// use sequoia_openpgp as openpgp; 260 /// # use openpgp::Result; 261 /// use openpgp::cert::prelude::*; 262 /// use openpgp::policy::StandardPolicy; 263 /// use openpgp::packet::signature::subpacket::{SubpacketTag, SubpacketValue}; 264 /// use openpgp::types::{Timestamp, Duration}; 265 /// 266 /// # fn main() -> Result<()> { 267 /// let p = &StandardPolicy::new(); 268 /// 269 /// let now = Timestamp::now(); 270 /// let validity_period = Duration::days(365)?; 271 /// 272 /// let (cert,_) = CertBuilder::new() 273 /// .set_creation_time(now) 274 /// .set_validity_period(validity_period) 275 /// .generate()?; 276 /// 277 /// let vc = cert.with_policy(p, now)?; 278 /// assert!(vc.alive().is_ok()); 279 /// # Ok(()) } 280 /// ``` 281 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 282 pub struct Duration(u32); 283 284 impl From<Duration> for u32 { 285 fn from(d: Duration) -> Self { 286 d.0 287 } 288 } 289 290 impl From<u32> for Duration { 291 fn from(d: u32) -> Self { 292 Duration(d) 293 } 294 } 295 296 impl TryFrom<SystemDuration> for Duration { 297 type Error = anyhow::Error; 298 299 fn try_from(d: SystemDuration) -> Result<Self> { 300 if d.as_secs() <= std::u32::MAX as u64 { 301 Ok(Duration(d.as_secs() as u32)) 302 } else { 303 Err(Error::InvalidArgument( 304 format!("Duration exceeds u32: {:?}", d)) 305 .into()) 306 } 307 } 308 } 309 310 impl From<Duration> for SystemDuration { 311 fn from(d: Duration) -> Self { 312 SystemDuration::new(d.0 as u64, 0) 313 } 314 } 315 316 impl From<Duration> for Option<SystemDuration> { 317 fn from(d: Duration) -> Self { 318 Some(d.into()) 319 } 320 } 321 322 impl fmt::Debug for Duration { 323 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 324 write!(f, "{:?}", SystemDuration::from(*self)) 325 } 326 } 327 328 impl Duration { 329 /// Returns a `Duration` with the given number of seconds. 330 pub fn seconds(n: u32) -> Duration { 331 n.into() 332 } 333 334 /// Returns a `Duration` with the given number of minutes, if 335 /// representable. 336 pub fn minutes(n: u32) -> Result<Duration> { 337 60u32.checked_mul(n).ok_or(()) 338 .map(Self::seconds) 339 .map_err(|_| Error::InvalidArgument( 340 format!("Not representable: {} minutes in seconds exceeds u32", 341 n)).into()) 342 } 343 344 /// Returns a `Duration` with the given number of hours, if 345 /// representable. 346 pub fn hours(n: u32) -> Result<Duration> { 347 60u32.checked_mul(n) 348 .ok_or(Error::InvalidArgument("".into()).into()) 349 .and_then(Self::minutes) 350 .map_err(|_| Error::InvalidArgument( 351 format!("Not representable: {} hours in seconds exceeds u32", 352 n)).into()) 353 } 354 355 /// Returns a `Duration` with the given number of days, if 356 /// representable. 357 pub fn days(n: u32) -> Result<Duration> { 358 24u32.checked_mul(n) 359 .ok_or(Error::InvalidArgument("".into()).into()) 360 .and_then(Self::hours) 361 .map_err(|_| Error::InvalidArgument( 362 format!("Not representable: {} days in seconds exceeds u32", 363 n)).into()) 364 } 365 366 /// Returns a `Duration` with the given number of weeks, if 367 /// representable. 368 pub fn weeks(n: u32) -> Result<Duration> { 369 7u32.checked_mul(n) 370 .ok_or(Error::InvalidArgument("".into()).into()) 371 .and_then(Self::days) 372 .map_err(|_| Error::InvalidArgument( 373 format!("Not representable: {} weeks in seconds exceeds u32", 374 n)).into()) 375 } 376 377 /// Returns the duration as seconds. 378 pub fn as_secs(self) -> u64 { 379 self.0 as u64 380 } 381 382 /// Rounds up to the given level of precision. 383 /// 384 /// If [`Timestamp::round_down`] is used to round the creation 385 /// timestamp of a key or signature down, then this function may 386 /// be used to round the corresponding expiration time up. This 387 /// ensures validity during the originally intended lifetime, 388 /// while avoiding the metadata leak associated with preserving 389 /// the originally intended expiration time. 390 /// 391 /// [`Timestamp::round_down`]: struct.Timestamp.html#method.round_down 392 /// 393 /// The given level `p` determines the resulting resolution of 394 /// `2^p` seconds. The default is `21`, which results in a 395 /// resolution of 24 days, or roughly a month. `p` must be lower 396 /// than 32. 397 /// 398 /// The upper limit `ceil` represents the maximum time to round up to. 399 pub fn round_up<P, C>(&self, precision: P, ceil: C) -> Result<Duration> 400 where P: Into<Option<u8>>, 401 C: Into<Option<SystemDuration>> 402 { 403 let p = precision.into().unwrap_or(21) as u32; 404 if p < 32 { 405 if let Some(sum) = self.0.checked_add((1 << p) - 1) { 406 let rounded = Self(sum & !((1 << p) - 1)); 407 match ceil.into() { 408 Some(ceil) => { 409 Ok(cmp::min(rounded, ceil.try_into()?)) 410 }, 411 None => Ok(rounded) 412 } 413 } else { 414 Ok(Self(std::u32::MAX)) 415 } 416 } else { 417 Err(Error::InvalidArgument( 418 format!("Invalid precision {}", p)).into()) 419 } 420 } 421 } 422 423 #[allow(unused)] 424 impl Timestamp { 425 pub(crate) const UNIX_EPOCH : Timestamp = Timestamp(0); 426 pub(crate) const MAX : Timestamp = Timestamp(u32::MAX); 427 428 // for y in $(seq 1970 2106); do echo " const Y$y : Timestamp = Timestamp($(date -u --date="Jan. 1, $y" '+%s'));"; done 429 pub(crate) const Y1970 : Timestamp = Timestamp(0); 430 pub(crate) const Y1971 : Timestamp = Timestamp(31536000); 431 pub(crate) const Y1972 : Timestamp = Timestamp(63072000); 432 pub(crate) const Y1973 : Timestamp = Timestamp(94694400); 433 pub(crate) const Y1974 : Timestamp = Timestamp(126230400); 434 pub(crate) const Y1975 : Timestamp = Timestamp(157766400); 435 pub(crate) const Y1976 : Timestamp = Timestamp(189302400); 436 pub(crate) const Y1977 : Timestamp = Timestamp(220924800); 437 pub(crate) const Y1978 : Timestamp = Timestamp(252460800); 438 pub(crate) const Y1979 : Timestamp = Timestamp(283996800); 439 pub(crate) const Y1980 : Timestamp = Timestamp(315532800); 440 pub(crate) const Y1981 : Timestamp = Timestamp(347155200); 441 pub(crate) const Y1982 : Timestamp = Timestamp(378691200); 442 pub(crate) const Y1983 : Timestamp = Timestamp(410227200); 443 pub(crate) const Y1984 : Timestamp = Timestamp(441763200); 444 pub(crate) const Y1985 : Timestamp = Timestamp(473385600); 445 pub(crate) const Y1986 : Timestamp = Timestamp(504921600); 446 pub(crate) const Y1987 : Timestamp = Timestamp(536457600); 447 pub(crate) const Y1988 : Timestamp = Timestamp(567993600); 448 pub(crate) const Y1989 : Timestamp = Timestamp(599616000); 449 pub(crate) const Y1990 : Timestamp = Timestamp(631152000); 450 pub(crate) const Y1991 : Timestamp = Timestamp(662688000); 451 pub(crate) const Y1992 : Timestamp = Timestamp(694224000); 452 pub(crate) const Y1993 : Timestamp = Timestamp(725846400); 453 pub(crate) const Y1994 : Timestamp = Timestamp(757382400); 454 pub(crate) const Y1995 : Timestamp = Timestamp(788918400); 455 pub(crate) const Y1996 : Timestamp = Timestamp(820454400); 456 pub(crate) const Y1997 : Timestamp = Timestamp(852076800); 457 pub(crate) const Y1998 : Timestamp = Timestamp(883612800); 458 pub(crate) const Y1999 : Timestamp = Timestamp(915148800); 459 pub(crate) const Y2000 : Timestamp = Timestamp(946684800); 460 pub(crate) const Y2001 : Timestamp = Timestamp(978307200); 461 pub(crate) const Y2002 : Timestamp = Timestamp(1009843200); 462 pub(crate) const Y2003 : Timestamp = Timestamp(1041379200); 463 pub(crate) const Y2004 : Timestamp = Timestamp(1072915200); 464 pub(crate) const Y2005 : Timestamp = Timestamp(1104537600); 465 pub(crate) const Y2006 : Timestamp = Timestamp(1136073600); 466 pub(crate) const Y2007 : Timestamp = Timestamp(1167609600); 467 pub(crate) const Y2008 : Timestamp = Timestamp(1199145600); 468 pub(crate) const Y2009 : Timestamp = Timestamp(1230768000); 469 pub(crate) const Y2010 : Timestamp = Timestamp(1262304000); 470 pub(crate) const Y2011 : Timestamp = Timestamp(1293840000); 471 pub(crate) const Y2012 : Timestamp = Timestamp(1325376000); 472 pub(crate) const Y2013 : Timestamp = Timestamp(1356998400); 473 pub(crate) const Y2014 : Timestamp = Timestamp(1388534400); 474 pub(crate) const Y2015 : Timestamp = Timestamp(1420070400); 475 pub(crate) const Y2016 : Timestamp = Timestamp(1451606400); 476 pub(crate) const Y2017 : Timestamp = Timestamp(1483228800); 477 pub(crate) const Y2018 : Timestamp = Timestamp(1514764800); 478 pub(crate) const Y2019 : Timestamp = Timestamp(1546300800); 479 pub(crate) const Y2020 : Timestamp = Timestamp(1577836800); 480 pub(crate) const Y2021 : Timestamp = Timestamp(1609459200); 481 pub(crate) const Y2022 : Timestamp = Timestamp(1640995200); 482 pub(crate) const Y2023 : Timestamp = Timestamp(1672531200); 483 pub(crate) const Y2024 : Timestamp = Timestamp(1704067200); 484 pub(crate) const Y2025 : Timestamp = Timestamp(1735689600); 485 pub(crate) const Y2026 : Timestamp = Timestamp(1767225600); 486 pub(crate) const Y2027 : Timestamp = Timestamp(1798761600); 487 pub(crate) const Y2028 : Timestamp = Timestamp(1830297600); 488 pub(crate) const Y2029 : Timestamp = Timestamp(1861920000); 489 pub(crate) const Y2030 : Timestamp = Timestamp(1893456000); 490 pub(crate) const Y2031 : Timestamp = Timestamp(1924992000); 491 pub(crate) const Y2032 : Timestamp = Timestamp(1956528000); 492 pub(crate) const Y2033 : Timestamp = Timestamp(1988150400); 493 pub(crate) const Y2034 : Timestamp = Timestamp(2019686400); 494 pub(crate) const Y2035 : Timestamp = Timestamp(2051222400); 495 pub(crate) const Y2036 : Timestamp = Timestamp(2082758400); 496 pub(crate) const Y2037 : Timestamp = Timestamp(2114380800); 497 pub(crate) const Y2038 : Timestamp = Timestamp(2145916800); 498 pub(crate) const Y2039 : Timestamp = Timestamp(2177452800); 499 pub(crate) const Y2040 : Timestamp = Timestamp(2208988800); 500 pub(crate) const Y2041 : Timestamp = Timestamp(2240611200); 501 pub(crate) const Y2042 : Timestamp = Timestamp(2272147200); 502 pub(crate) const Y2043 : Timestamp = Timestamp(2303683200); 503 pub(crate) const Y2044 : Timestamp = Timestamp(2335219200); 504 pub(crate) const Y2045 : Timestamp = Timestamp(2366841600); 505 pub(crate) const Y2046 : Timestamp = Timestamp(2398377600); 506 pub(crate) const Y2047 : Timestamp = Timestamp(2429913600); 507 pub(crate) const Y2048 : Timestamp = Timestamp(2461449600); 508 pub(crate) const Y2049 : Timestamp = Timestamp(2493072000); 509 pub(crate) const Y2050 : Timestamp = Timestamp(2524608000); 510 pub(crate) const Y2051 : Timestamp = Timestamp(2556144000); 511 pub(crate) const Y2052 : Timestamp = Timestamp(2587680000); 512 pub(crate) const Y2053 : Timestamp = Timestamp(2619302400); 513 pub(crate) const Y2054 : Timestamp = Timestamp(2650838400); 514 pub(crate) const Y2055 : Timestamp = Timestamp(2682374400); 515 pub(crate) const Y2056 : Timestamp = Timestamp(2713910400); 516 pub(crate) const Y2057 : Timestamp = Timestamp(2745532800); 517 pub(crate) const Y2058 : Timestamp = Timestamp(2777068800); 518 pub(crate) const Y2059 : Timestamp = Timestamp(2808604800); 519 pub(crate) const Y2060 : Timestamp = Timestamp(2840140800); 520 pub(crate) const Y2061 : Timestamp = Timestamp(2871763200); 521 pub(crate) const Y2062 : Timestamp = Timestamp(2903299200); 522 pub(crate) const Y2063 : Timestamp = Timestamp(2934835200); 523 pub(crate) const Y2064 : Timestamp = Timestamp(2966371200); 524 pub(crate) const Y2065 : Timestamp = Timestamp(2997993600); 525 pub(crate) const Y2066 : Timestamp = Timestamp(3029529600); 526 pub(crate) const Y2067 : Timestamp = Timestamp(3061065600); 527 pub(crate) const Y2068 : Timestamp = Timestamp(3092601600); 528 pub(crate) const Y2069 : Timestamp = Timestamp(3124224000); 529 pub(crate) const Y2070 : Timestamp = Timestamp(3155760000); 530 pub(crate) const Y2071 : Timestamp = Timestamp(3187296000); 531 pub(crate) const Y2072 : Timestamp = Timestamp(3218832000); 532 pub(crate) const Y2073 : Timestamp = Timestamp(3250454400); 533 pub(crate) const Y2074 : Timestamp = Timestamp(3281990400); 534 pub(crate) const Y2075 : Timestamp = Timestamp(3313526400); 535 pub(crate) const Y2076 : Timestamp = Timestamp(3345062400); 536 pub(crate) const Y2077 : Timestamp = Timestamp(3376684800); 537 pub(crate) const Y2078 : Timestamp = Timestamp(3408220800); 538 pub(crate) const Y2079 : Timestamp = Timestamp(3439756800); 539 pub(crate) const Y2080 : Timestamp = Timestamp(3471292800); 540 pub(crate) const Y2081 : Timestamp = Timestamp(3502915200); 541 pub(crate) const Y2082 : Timestamp = Timestamp(3534451200); 542 pub(crate) const Y2083 : Timestamp = Timestamp(3565987200); 543 pub(crate) const Y2084 : Timestamp = Timestamp(3597523200); 544 pub(crate) const Y2085 : Timestamp = Timestamp(3629145600); 545 pub(crate) const Y2086 : Timestamp = Timestamp(3660681600); 546 pub(crate) const Y2087 : Timestamp = Timestamp(3692217600); 547 pub(crate) const Y2088 : Timestamp = Timestamp(3723753600); 548 pub(crate) const Y2089 : Timestamp = Timestamp(3755376000); 549 pub(crate) const Y2090 : Timestamp = Timestamp(3786912000); 550 pub(crate) const Y2091 : Timestamp = Timestamp(3818448000); 551 pub(crate) const Y2092 : Timestamp = Timestamp(3849984000); 552 pub(crate) const Y2093 : Timestamp = Timestamp(3881606400); 553 pub(crate) const Y2094 : Timestamp = Timestamp(3913142400); 554 pub(crate) const Y2095 : Timestamp = Timestamp(3944678400); 555 pub(crate) const Y2096 : Timestamp = Timestamp(3976214400); 556 pub(crate) const Y2097 : Timestamp = Timestamp(4007836800); 557 pub(crate) const Y2098 : Timestamp = Timestamp(4039372800); 558 pub(crate) const Y2099 : Timestamp = Timestamp(4070908800); 559 pub(crate) const Y2100 : Timestamp = Timestamp(4102444800); 560 pub(crate) const Y2101 : Timestamp = Timestamp(4133980800); 561 pub(crate) const Y2102 : Timestamp = Timestamp(4165516800); 562 pub(crate) const Y2103 : Timestamp = Timestamp(4197052800); 563 pub(crate) const Y2104 : Timestamp = Timestamp(4228588800); 564 pub(crate) const Y2105 : Timestamp = Timestamp(4260211200); 565 pub(crate) const Y2106 : Timestamp = Timestamp(4291747200); 566 } 567 568 #[cfg(any(test, feature = "quickcheck"))] 569 impl Arbitrary for Duration { 570 fn arbitrary<G: Gen>(g: &mut G) -> Self { 571 Duration(u32::arbitrary(g)) 572 } 573 } 574 575 /// Normalizes the given SystemTime to the resolution OpenPGP 576 /// supports. 577 pub(crate) fn normalize_systemtime(t: SystemTime) -> SystemTime { 578 UNIX_EPOCH + SystemDuration::new( 579 t.duration_since(UNIX_EPOCH).unwrap().as_secs(), 0) 580 } 581 582 #[cfg(test)] 583 mod tests { 584 use super::*; 585 586 quickcheck! { 587 fn timestamp_round_down(t: Timestamp) -> bool { 588 let u = t.round_down(None, None).unwrap(); 589 assert!(u <= t); 590 assert_eq!(u32::from(u) & 0b1_1111_1111_1111_1111_1111, 0); 591 assert!(u32::from(t) - u32::from(u) < 2_u32.pow(21)); 592 true 593 } 594 } 595 596 #[test] 597 fn timestamp_round_down_floor() -> Result<()> { 598 let t = Timestamp(1585753307); 599 let floor = t.checked_sub(Duration::weeks(1).unwrap()).unwrap(); 600 601 let u = t.round_down(21, floor).unwrap(); 602 assert!(u < t); 603 assert!(floor < u); 604 assert_eq!(u32::from(u) & 0b1_1111_1111_1111_1111_1111, 0); 605 606 let floor = t.checked_sub(Duration::days(1).unwrap()).unwrap(); 607 608 let u = t.round_down(21, floor).unwrap(); 609 assert_eq!(u, floor); 610 Ok(()) 611 } 612 613 quickcheck! { 614 fn duration_round_up(d: Duration) -> bool { 615 let u = d.round_up(None, None).unwrap(); 616 assert!(d <= u); 617 assert_eq!(u32::from(u) & 0b1_1111_1111_1111_1111_1111, 0); 618 assert!(u32::from(u) - u32::from(d) < 2_u32.pow(21)); 619 true 620 } 621 } 622 623 #[test] 624 fn duration_round_up_ceil() -> Result<()> { 625 let d = Duration(123); 626 627 let ceil = Duration(2_u32.pow(23)); 628 629 let u = d.round_up(21, ceil)?; 630 assert!(d < u); 631 assert!(u < ceil); 632 assert_eq!(u32::from(u) & 0b1_1111_1111_1111_1111_1111, 0); 633 634 let ceil = Duration::days(1).unwrap(); 635 636 let u = d.round_up(21, ceil)?; 637 assert!(d < u); 638 assert_eq!(u, ceil); 639 640 Ok(()) 641 } 642 } 643