275 lines
7.7 KiB
Rust
275 lines
7.7 KiB
Rust
use dever_runtime::time::calendar::{Date, DateTime, Time};
|
|
use dever_runtime::value::secret::Secret;
|
|
use sha2::{Digest, Sha256};
|
|
|
|
fn primitive_fault() -> Fault {
|
|
&FaultInfo {
|
|
message: "extended primitive failed",
|
|
source: "extended-primitives-reference",
|
|
line: 1,
|
|
column: 1,
|
|
}
|
|
}
|
|
|
|
fn digest_score(bytes: &dever_runtime::Bytes) -> u64 {
|
|
bytes.iter().fold(0u64, |score, byte| {
|
|
score.wrapping_mul(31).wrapping_add(u64::from(*byte))
|
|
})
|
|
}
|
|
|
|
fn sha_reference(bytes: &dever_runtime::Bytes) -> Result<dever_runtime::Bytes, Fault> {
|
|
Ok(Sha256::digest(bytes).to_vec().into())
|
|
}
|
|
|
|
struct HmacCase {
|
|
key: Secret,
|
|
bytes: dever_runtime::Bytes,
|
|
}
|
|
|
|
fn hmac_generated(values: &[HmacCase]) -> Result<dever_runtime::Bytes, Fault> {
|
|
let Some(value) = values.first() else {
|
|
return Ok(dever_runtime::Bytes::new());
|
|
};
|
|
EXT_HMAC(&value.key, &value.bytes)
|
|
}
|
|
|
|
// 共用批准的 Secret 接收点;不读取密钥内部字节。
|
|
fn hmac_reference(values: &[HmacCase]) -> Result<dever_runtime::Bytes, Fault> {
|
|
Ok(values
|
|
.first()
|
|
.map_or_else(Vec::new, |value| {
|
|
dever_runtime::crypto::hmac_sha256(&value.key, &value.bytes)
|
|
})
|
|
.into())
|
|
}
|
|
|
|
fn datetime_generated(values: &[String]) -> Result<Vec<String>, Fault> {
|
|
EXT_DATETIME(values).map_err(|_| primitive_fault())
|
|
}
|
|
|
|
fn datetime_reference(values: &[String]) -> Result<Vec<String>, Fault> {
|
|
values
|
|
.iter()
|
|
.map(|value| {
|
|
DateTime::parse(value)
|
|
.and_then(DateTime::format)
|
|
.map_err(|_| primitive_fault())
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn date_generated(values: &[String]) -> Result<Vec<String>, Fault> {
|
|
EXT_DATE(values).map_err(|_| primitive_fault())
|
|
}
|
|
|
|
fn date_reference(values: &[String]) -> Result<Vec<String>, Fault> {
|
|
values
|
|
.iter()
|
|
.map(|value| {
|
|
Date::parse(value)
|
|
.and_then(Date::format)
|
|
.map_err(|_| primitive_fault())
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn time_generated(values: &[String]) -> Result<Vec<String>, Fault> {
|
|
EXT_TIME(values).map_err(|_| primitive_fault())
|
|
}
|
|
|
|
fn time_reference(values: &[String]) -> Result<Vec<String>, Fault> {
|
|
values
|
|
.iter()
|
|
.map(|value| {
|
|
Time::parse(value)
|
|
.and_then(Time::format)
|
|
.map_err(|_| primitive_fault())
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn text_score(values: &Vec<String>) -> u64 {
|
|
values
|
|
.iter()
|
|
.flat_map(|value| value.bytes())
|
|
.fold(0u64, |score, byte| {
|
|
score.wrapping_mul(31).wrapping_add(u64::from(byte))
|
|
})
|
|
}
|
|
|
|
fn uuid_generated(values: &[String]) -> Result<Vec<Option<String>>, Fault> {
|
|
EXT_UUID(values)
|
|
}
|
|
|
|
fn uuid_reference(values: &[String]) -> Result<Vec<Option<String>>, Fault> {
|
|
Ok(values
|
|
.iter()
|
|
.map(|value| {
|
|
if value.len() != 36 {
|
|
return None;
|
|
}
|
|
uuid::Uuid::try_parse(value)
|
|
.ok()
|
|
.map(|value| value.hyphenated().to_string())
|
|
})
|
|
.collect())
|
|
}
|
|
|
|
fn uuid_score(values: &Vec<Option<String>>) -> u64 {
|
|
values.iter().fold(0u64, |score, value| {
|
|
value.as_ref().map_or(score.wrapping_add(1), |value| {
|
|
value.bytes().fold(score.wrapping_add(2), |score, byte| {
|
|
score.wrapping_mul(31).wrapping_add(u64::from(byte))
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
fn check_primitives() {
|
|
assert_eq!(
|
|
EXT_SHA256(&dever_runtime::Bytes::from_static(b"abc"))
|
|
.unwrap()
|
|
.as_ref(),
|
|
[
|
|
0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
|
|
0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
|
|
0xf2, 0x00, 0x15, 0xad,
|
|
]
|
|
);
|
|
// 沿用已有密码学验收的公开向量,不使用真实凭据。
|
|
let vector = [HmacCase {
|
|
key: Secret::from_input(vec![0x0b; 20]),
|
|
bytes: dever_runtime::Bytes::from_static(b"Hi There"),
|
|
}];
|
|
assert_eq!(
|
|
hmac_generated(&vector).unwrap().as_ref(),
|
|
[
|
|
0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b,
|
|
0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
|
|
0x2e, 0x32, 0xcf, 0xf7,
|
|
]
|
|
);
|
|
assert_eq!(
|
|
hmac_generated(&vector).unwrap(),
|
|
hmac_reference(&vector).unwrap()
|
|
);
|
|
assert_eq!(
|
|
datetime_generated(&["2024-02-29T12:34:56.12+08:00".into()]).unwrap(),
|
|
["2024-02-29T04:34:56.120Z"]
|
|
);
|
|
assert_eq!(
|
|
time_generated(&["12:34:56.000".into()]).unwrap(),
|
|
["12:34:56"]
|
|
);
|
|
for value in ["2023-02-29", "2024-2-29"] {
|
|
let values = [value.to_owned()];
|
|
assert!(date_generated(&values).is_err());
|
|
assert!(date_reference(&values).is_err());
|
|
}
|
|
for value in ["24:00:00", "12:34:56.1"] {
|
|
let values = [value.to_owned()];
|
|
assert!(time_generated(&values).is_err());
|
|
assert!(time_reference(&values).is_err());
|
|
}
|
|
let values = ["2024-02-29T00:00:00.1234Z".to_owned()];
|
|
assert!(datetime_generated(&values).is_err());
|
|
assert!(datetime_reference(&values).is_err());
|
|
}
|
|
|
|
fn main() {
|
|
check_primitives();
|
|
println!("case,sample,implementation,elapsed_ns,checksum");
|
|
for size in [0usize, 64, 4096] {
|
|
let bytes = dever_runtime::Bytes::from(vec![0x61; size]);
|
|
compare_bytes(
|
|
&format!("crypto_sha256_{size}"),
|
|
&bytes,
|
|
2000,
|
|
EXT_SHA256,
|
|
sha_reference,
|
|
digest_score,
|
|
);
|
|
let values = [HmacCase {
|
|
key: Secret::from_input(vec![0x0b; 20]),
|
|
bytes,
|
|
}];
|
|
compare_named(
|
|
&format!("crypto_hmac_{size}_shared_runtime"),
|
|
&values,
|
|
2000,
|
|
hmac_generated,
|
|
hmac_reference,
|
|
digest_score,
|
|
"rust_runtime",
|
|
);
|
|
}
|
|
// 日历参照保留相同精度、年份范围、非法输入和 UTC 规范化规则。
|
|
let datetimes = [
|
|
"1970-01-01T00:00:00Z",
|
|
"2024-02-29T12:34:56.12+08:00",
|
|
"1969-12-31T23:59:59.999Z",
|
|
]
|
|
.map(str::to_owned);
|
|
let dates = ["2024-02-29", "2000-01-01", "9999-12-31"].map(str::to_owned);
|
|
let times = ["00:00:00", "12:34:56.000", "23:59:59.999"].map(str::to_owned);
|
|
compare_named(
|
|
"calendar_datetime_shared_runtime",
|
|
&datetimes,
|
|
2000,
|
|
datetime_generated,
|
|
datetime_reference,
|
|
text_score,
|
|
"rust_runtime",
|
|
);
|
|
compare_named(
|
|
"calendar_date_shared_runtime",
|
|
&dates,
|
|
2000,
|
|
date_generated,
|
|
date_reference,
|
|
text_score,
|
|
"rust_runtime",
|
|
);
|
|
compare_named(
|
|
"calendar_time_shared_runtime",
|
|
×,
|
|
2000,
|
|
time_generated,
|
|
time_reference,
|
|
text_score,
|
|
"rust_runtime",
|
|
);
|
|
let valid = [
|
|
"550E8400-E29B-41D4-A716-446655440000",
|
|
"00000000-0000-0000-0000-000000000000",
|
|
]
|
|
.map(str::to_owned);
|
|
assert_eq!(
|
|
uuid_generated(&valid).unwrap()[0].as_deref(),
|
|
Some("550e8400-e29b-41d4-a716-446655440000")
|
|
);
|
|
let invalid = [
|
|
"",
|
|
"550e8400e29b41d4a716446655440000",
|
|
"00000000-0000-0000-0000-00000000000-",
|
|
]
|
|
.map(str::to_owned);
|
|
assert_eq!(uuid_generated(&invalid).unwrap(), vec![None; invalid.len()]);
|
|
compare(
|
|
"uuid_parse_format",
|
|
&valid,
|
|
2000,
|
|
uuid_generated,
|
|
uuid_reference,
|
|
uuid_score,
|
|
);
|
|
compare(
|
|
"uuid_parse_invalid",
|
|
&invalid,
|
|
2000,
|
|
uuid_generated,
|
|
uuid_reference,
|
|
uuid_score,
|
|
);
|
|
}
|