From 2f61ae967ca7e694aa6edee71d20dae653c821fd Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Tue, 27 Aug 2024 08:42:03 -0600 Subject: [PATCH] add date time scalars Signed-off-by: Michael Lodder --- Cargo.toml | 17 ++++++------- src/claim/number.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 81018a1..9583ce4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,35 +3,36 @@ name = "credx" version = "0.1.0" edition = "2021" +# NOTE: Please keep dependencies sorted alphabetically. [dependencies] +base64 = "0.22" +blsful = "2.5" bulletproofs = { version = "4.0.0", git = "https://github.com/cryptidtech/bulletproofs" } +chrono = "0.4" hex = "0.4" indexmap = "2" +log = "0.4" merlin = "3" +maplit = "1" rand = "0.8" rand_chacha = "0.3" rand_core = "0.6" regex = "1" +rmp-serde = "1.3" serde = { version = "1", features = ["serde_derive"] } serde_bare = "0.5" serde_json = "1" serde_regex = "1" sha2 = "0.10" sha3 = "0.10" -blsful = "2.5" subtle = "2.5" uint-zigzag = { version = "0.2", features = ["std"] } +uuid = {version = "1.10", features = ["v4"]} zeroize = "1" -log = "0.4.20" -base64 = "0.22.1" -rmp-serde = "1.3.0" -chrono = "0.4.35" -maplit = "1" -uuid = {version = "1.8.0", features = ["v4"]} [dev-dependencies] -lazy_static = "1.4.0" +lazy_static = "1.5.0" maplit = "1" serde_cbor = "0.11" sha2 = "0.10" diff --git a/src/claim/number.rs b/src/claim/number.rs index f153074..0a4974b 100644 --- a/src/claim/number.rs +++ b/src/claim/number.rs @@ -1,6 +1,7 @@ use super::{Claim, ClaimType}; -use crate::utils::get_num_scalar; +use crate::{error::Error, utils::get_num_scalar}; use blsful::inner_types::Scalar; +use chrono::Datelike; use core::{ fmt::{self, Display, Formatter}, hash::{Hash, Hasher}, @@ -67,3 +68,58 @@ impl Claim for NumberClaim { self.value } } + +impl NumberClaim { + /// RFC3339 dates are in the format of `YYYY-MM-DD` and are treated + /// as a number claim with the value of `YYYYMMDD`. + pub fn parse_rfc3339_date>(date: S) -> Result { + // Use chrono to check whether the date is valid. + // Invalid dates include days greater than 31, months greater than 12, etc. + // and checks whether the month even supports the number of days specified + // like February 30th is never valid. + let dt = chrono::NaiveDate::parse_from_str(date.as_ref(), "%Y-%m-%d") + .map_err(|_| Error::InvalidClaimData("Invalid RFC3339 date"))?; + // There's no need to zero center unless we're dealing with a dates BC + let mut value = dt.year().to_string(); + if dt.month() < 10 { + value.push('0'); + } + value.push_str(&dt.month().to_string()); + if dt.day() < 10 { + value.push('0'); + } + value.push_str(&dt.day().to_string()); + Ok(Self::from(value.parse::().map_err(|_| { + Error::InvalidClaimData("Invalid RFC3339 date") + })?)) + } + + /// RFC3339 DateTimes are in the format of `YYYY-MM-DDTHH:MM:SSZ` and are treated + /// as a number claim representing the number of seconds since the Unix epoch. + pub fn parse_rfc3339_datetime>(datetime: S) -> Result { + let dt = chrono::DateTime::parse_from_rfc3339(datetime.as_ref()) + .map_err(|_| Error::InvalidClaimData("Invalid RFC3339 datetime"))?; + // There's no need to zero center unless we're dealing with a dates BC + Ok(Self::from(dt.timestamp() as isize)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_rfc3339_date() { + let claim = NumberClaim::parse_rfc3339_date("2021-01-01").unwrap(); + assert_eq!(claim.value, 20210101); + + let claim = NumberClaim::parse_rfc3339_date("1982-12-31").unwrap(); + assert_eq!(claim.value, 19821231); + } + + #[test] + fn test_rfc3339_datetime() { + let claim = NumberClaim::parse_rfc3339_datetime("2021-01-01T00:00:00Z").unwrap(); + assert_eq!(claim.value, 1609459200); + } +} \ No newline at end of file