Skip to content

Commit

Permalink
Merge pull request #125 from alan-turing-institute/root-event-date
Browse files Browse the repository at this point in the history
Root event date
  • Loading branch information
thobson88 authored Oct 13, 2023
2 parents b9d0c67 + 07ab3c3 commit 5088333
Show file tree
Hide file tree
Showing 21 changed files with 871 additions and 163 deletions.
6 changes: 3 additions & 3 deletions trustchain-api/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,9 @@ mod tests {
use trustchain_ion::verifier::IONVerifier;

// The root event time of DID documents in `trustchain-ion/src/data.rs` used for unit tests and the test below.
const ROOT_EVENT_TIME_1: u32 = 1666265405;
const ROOT_EVENT_TIME_1: u64 = 1666265405;

const TEST_UNSIGNED_VC: &str = r##"{
const TEST_UNSIGNED_VC: &str = r#"{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
Expand All @@ -283,7 +283,7 @@ mod tests {
}
}
}
"##;
"#;

#[ignore = "requires a running Sidetree node listening on http://localhost:3000"]
#[tokio::test]
Expand Down
7 changes: 4 additions & 3 deletions trustchain-cli/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Some(time) => time.parse::<u32>().unwrap(),
None => cli_config().root_event_time,
};
let did_chain = TrustchainAPI::verify(did, root_event_time, &verifier).await?;
let did_chain =
TrustchainAPI::verify(did, root_event_time.into(), &verifier).await?;
println!("{did_chain}");
}
_ => panic!("Unrecognised DID subcommand."),
Expand Down Expand Up @@ -186,8 +187,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Some(("verify", sub_matches)) => {
let verbose = sub_matches.get_one::<u8>("verbose");
let root_event_time = match sub_matches.get_one::<String>("root_event_time") {
Some(time) => time.parse::<u32>().unwrap(),
None => cli_config().root_event_time,
Some(time) => time.parse::<u64>().unwrap(),
None => cli_config().root_event_time.into(),
};
// Deserialize
let credential: Credential =
Expand Down
4 changes: 2 additions & 2 deletions trustchain-cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ mod tests {

#[test]
fn test_deserialize() {
let config_string = r##"
let config_string = r#"
[cli]
root_event_time = 1666971942
ion_endpoint.host = "http://127.0.0.1"
ion_endpoint.port = 3000
[non_core]
key = "value"
"##;
"#;

let config: CLIConfig = parse_toml(config_string);

Expand Down
4 changes: 2 additions & 2 deletions trustchain-core/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ mod tests {
TEST_TRUSTCHAIN_DOCUMENT_METADATA,
};

const ROOT_SIGNING_KEYS: &str = r##"
const ROOT_SIGNING_KEYS: &str = r#"
[
{
"kty": "EC",
Expand All @@ -318,7 +318,7 @@ mod tests {
"y": "kWvmS7ZOvDUhF8syO08PBzEpEk3BZMuukkvEJOKSjqE"
}
]
"##;
"#;

#[test]
fn test_get_proof() -> Result<(), Box<dyn std::error::Error>> {
Expand Down
52 changes: 26 additions & 26 deletions trustchain-core/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ pub const TEST_SIDETREE_DOCUMENT_MULTIPLE_KEYS: &str = r##"
// Previous versions that don't match example keys, to remove:
// "recoveryCommitment" : "EiBKWQyomumgZvqiRVZnqwA2-7RVZ6Xr-cwDRmeXJT_k9g",
// "updateCommitment" : "EiCe3q-ZByJnzI6CwGIDj-M67W-Yv78L3ejxcuEDxnWzMg"
pub const TEST_SIDETREE_DOCUMENT_METADATA: &str = r##"
pub const TEST_SIDETREE_DOCUMENT_METADATA: &str = r#"
{
"canonicalId" : "did:ion:test:EiCBr7qGDecjkR2yUBhn3aNJPUR3TSEOlkpNcL0Q5Au9ZQ",
"method" : {
Expand All @@ -283,12 +283,12 @@ pub const TEST_SIDETREE_DOCUMENT_METADATA: &str = r##"
"updateCommitment" : "EiBWPR1JNdAQ4j3ZMqurb4rt10NA7s17lztFF9OIcEO3ew"
}
}
"##;
"#;

// Previous versions that don't match example keys, to remove:
// "recoveryCommitment" : "EiBKWQyomumgZvqiRVZnqwA2-7RVZ6Xr-cwDRmeXJT_k9g",
// "updateCommitment" : "EiCe3q-ZByJnzI6CwGIDj-M67W-Yv78L3ejxcuEDxnWzMg"
pub const TEST_TRUSTCHAIN_DOCUMENT_METADATA: &str = r##"
pub const TEST_TRUSTCHAIN_DOCUMENT_METADATA: &str = r#"
{
"canonicalId" : "did:ion:test:EiCBr7qGDecjkR2yUBhn3aNJPUR3TSEOlkpNcL0Q5Au9ZQ",
"method" : {
Expand All @@ -302,7 +302,7 @@ pub const TEST_TRUSTCHAIN_DOCUMENT_METADATA: &str = r##"
"proofValue" : "eyJhbGciOiJFUzI1NksifQ.IkVpQmNiTkRRcjZZNHNzZGc5QXo4eC1qNy1yS1FuNWk5T2Q2S3BjZ2c0RU1KOXci.Nii8p38DtzyurmPHO9sV2JLSH7-Pv-dCKQ0Y-H34rplwhhwca2nSra4ZofcUsHCG6u1oKJ0x4AmMUD2_3UIhRA"
}
}
"##;
"#;

pub const TEST_SIDETREE_DOCUMENT_WITH_CONTROLLER: &str = r##"
{
Expand Down Expand Up @@ -396,7 +396,7 @@ pub const TEST_TRUSTCHAIN_DOCUMENT: &str = r##"
}
"##;

pub const TEST_SIGNING_KEYS: &str = r##"[
pub const TEST_SIGNING_KEYS: &str = r#"[
{
"kty": "EC",
"crv": "secp256k1",
Expand All @@ -412,49 +412,49 @@ pub const TEST_SIGNING_KEYS: &str = r##"[
"d": "U7pUq3BovVnYT1mi1lds60wbueUKb5GobV_WvjOuY14"
}
]
"##;
"#;

pub const TEST_UPDATE_KEY: &str = r##"{
pub const TEST_UPDATE_KEY: &str = r#"{
"kty": "EC",
"crv": "secp256k1",
"x": "2hm19BwmXmR8Vfuw2XbGrusm89Pg6dyExlzDfc-CiM8",
"y": "uFjW0fKdhHaY4c_5E9Wkk3cPi9sJ5rP3oyl1ssV_X6A",
"d": "Z2vJqNRjbWvJX2NzABKlHI2V00HWmV2KNI5P4mmxRbg"
}"##;
}"#;

pub const TEST_NEXT_UPDATE_KEY: &str = r##"{
pub const TEST_NEXT_UPDATE_KEY: &str = r#"{
"kty": "EC",
"crv": "secp256k1",
"x": "hm_Pj46yibXbFNyARPXfOKIAEI_UKqfmZwzZDfbUSSk",
"y": "Djxgs6Ex71m6K0QCrn4l2naNo4F6IYXfu0LrBhW2RQU",
"d": "rAUu7DWaQ2ceSap_NzJNj1YOD2yP_bf1JqabuQJz6rc"
}"##;
}"#;

pub const TEST_RECOVERY_KEY: &str = r##"{
pub const TEST_RECOVERY_KEY: &str = r#"{
"kty": "EC",
"crv": "secp256k1",
"x": "_Z1JRmGwvj0jIpDW-QF0dmQnAL8D_FuNg2WxF7uJSYo",
"y": "orKbmG6L6kRugAB2OWzWNgulXRfyOR06GTm353Er--c",
"d": "YobJpI7p7T5dfU0cDRE4SQwp0eOFR6LOGrsqZE1GG1A"
}"##;
}"#;

pub const TEST_ROOT_SIGNING_PK: &str = r##"
pub const TEST_ROOT_SIGNING_PK: &str = r#"
{
"kty": "EC",
"crv": "secp256k1",
"x": "7ReQHHysGxbyuKEQmspQOjL7oQUqDTldTHuc9V3-yso",
"y": "kWvmS7ZOvDUhF8syO08PBzEpEk3BZMuukkvEJOKSjqE"
}
"##;
"#;

pub const TEST_ROOT_PLUS_1_SIGNING_KEY: &str = r##"
pub const TEST_ROOT_PLUS_1_SIGNING_KEY: &str = r#"
{
"kty": "EC",
"crv": "secp256k1",
"x": "aApKobPO8H8wOv-oGT8K3Na-8l-B1AE3uBZrWGT6FJU",
"y": "dspEqltAtlTKJ7cVRP_gMMknyDPqUw-JHlpwS2mFuh0"
}
"##;
"#;

pub const TEST_ROOT_DOCUMENT: &str = r##"
{
Expand Down Expand Up @@ -599,7 +599,7 @@ pub const TEST_ROOT_PLUS_2_DOCUMENT: &str = r##"
}
"##;

pub const TEST_ROOT_DOCUMENT_METADATA: &str = r##"
pub const TEST_ROOT_DOCUMENT_METADATA: &str = r#"
{
"canonicalId": "did:ion:test:EiCClfEdkTv_aM3UnBBhlOV89LlGhpQAbfeZLFdFxVFkEg",
"method": {
Expand All @@ -608,9 +608,9 @@ pub const TEST_ROOT_DOCUMENT_METADATA: &str = r##"
"recoveryCommitment": "EiCymv17OGBAs7eLmm4BIXDCQBVhdOUAX5QdpIrN4SDE5w"
}
}
"##;
"#;

pub const TEST_ROOT_PLUS_1_DOCUMENT_METADATA: &str = r##"
pub const TEST_ROOT_PLUS_1_DOCUMENT_METADATA: &str = r#"
{
"proof": {
"type": "JsonWebSignature2020",
Expand All @@ -624,22 +624,22 @@ pub const TEST_ROOT_PLUS_1_DOCUMENT_METADATA: &str = r##"
"updateCommitment": "EiA0-GpdeoAa4v0-K4YCHoNTjAPsoroDy7pleDIc4a3_QQ"
}
}
"##;
"#;

/// Root JWK public key
pub const TEST_ROOT_JWK_PK: &str = r##"
pub const TEST_ROOT_JWK_PK: &str = r#"
{
"kty": "EC",
"crv": "secp256k1",
"x": "7ReQHHysGxbyuKEQmspQOjL7oQUqDTldTHuc9V3-yso",
"y": "kWvmS7ZOvDUhF8syO08PBzEpEk3BZMuukkvEJOKSjqE"
}
"##;
"#;

/// Proof value from metadata
pub const TEST_ROOT_PLUS_1_JWT: &str = "eyJhbGciOiJFUzI1NksifQ.IkVpQXM5dkx2SmdaNkFHMk5XbUFmTnBrbl9EMlNSSUFSa2tCWE9kajZpMk84Umci.awNd-_O1N1ycZ6i_BxeLGV14ok51Ii2x9f1FBBCflyAWw773sqiHvQRGHIMBebKMnzbxVybFu2qUEPWUuRAC9g";

pub const TEST_ROOT_PLUS_2_DOCUMENT_METADATA: &str = r##"
pub const TEST_ROOT_PLUS_2_DOCUMENT_METADATA: &str = r#"
{
"canonicalId": "did:ion:test:EiAtHHKFJWAk5AsM3tgCut3OiBY4ekHTf66AAjoysXL65Q",
"method": {
Expand All @@ -653,7 +653,7 @@ pub const TEST_ROOT_PLUS_2_DOCUMENT_METADATA: &str = r##"
"type": "JsonWebSignature2020"
}
}
"##;
"#;
/// Proof value from metadata
pub const TEST_ROOT_PLUS_2_JWT: &str = "eyJhbGciOiJFUzI1NksifQ.IkVpQTNtT25QRklDbTdyc2ljVjRIaFMtNjhrT21xMndqa2tlMEtkRnkzQWlWZlEi.Fxlbm8osH2O5KOQ9sS21bypT_WoWxVD8toCU4baBnLk_gOxiOy_n3cMFMVANJ8usPrKAfRFeC27ATTkWBYZzuw";

Expand Down Expand Up @@ -1032,7 +1032,7 @@ pub const TEST_DID_CHAIN_REVERSED: &str = r##"
"##;

/// Test credential: no issuer is present for the unit test
pub const TEST_CREDENTIAL: &str = r##"{
pub const TEST_CREDENTIAL: &str = r#"{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1",
Expand All @@ -1054,4 +1054,4 @@ pub const TEST_CREDENTIAL: &str = r##"{
}
}
}
"##;
"#;
28 changes: 26 additions & 2 deletions trustchain-core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use ssi::did::{Document, ServiceEndpoint, VerificationMethod, VerificationMethod
use ssi::jwk::JWK;
use ssi::one_or_many::OneOrMany;
use std::path::{Path, PathBuf};

use std::sync::Once;

/// Gets the type of an object as a String. For diagnostic purposes (debugging) only.
Expand Down Expand Up @@ -99,6 +100,11 @@ pub fn get_did_suffix(did: &str) -> &str {
did.split(':').last().unwrap()
}

/// Converts a short-form DID into a complete DID.
pub fn get_did_from_suffix(did_suffix: &str, method_and_network: &str) -> String {
format!("did:{method_and_network}:{did_suffix}")
}

/// [`JSON_CANONICALIZATION_SCHEME`](https://identity.foundation/sidetree/spec/v1.0.0/#json-canonicalization-scheme)
pub fn canonicalize<T: Serialize + ?Sized>(value: &T) -> Result<String, serde_json::Error> {
serde_jcs::to_string(value)
Expand Down Expand Up @@ -302,6 +308,24 @@ mod tests {
};
use ssi::did::Document;

#[test]
fn test_get_did_from_suffix() {
let did_suffix = "EiCClfEdkTv_aM3UnBBhlOV89LlGhpQAbfeZLFdFxVFkEg";
let mut method_and_network = "ion";
let result = get_did_from_suffix(did_suffix, method_and_network);
assert_eq!(
result,
"did:ion:EiCClfEdkTv_aM3UnBBhlOV89LlGhpQAbfeZLFdFxVFkEg"
);

method_and_network = "ion:test";
let result = get_did_from_suffix(did_suffix, method_and_network);
assert_eq!(
result,
"did:ion:test:EiCClfEdkTv_aM3UnBBhlOV89LlGhpQAbfeZLFdFxVFkEg"
);
}

#[test]
fn test_generate_key() {
let result = generate_key();
Expand Down Expand Up @@ -456,12 +480,12 @@ mod tests {
assert!(!json_contains(&candidate, &expected));

// Entire expected object nested:
let exp_str = r##"{"publicKeyJwk" : {
let exp_str = r#"{"publicKeyJwk" : {
"crv": "secp256k1",
"kty": "EC",
"x": "7ReQHHysGxbyuKEQmspQOjL7oQUqDTldTHuc9V3-yso",
"y": "kWvmS7ZOvDUhF8syO08PBzEpEk3BZMuukkvEJOKSjqE"
}}"##;
}}"#;

let expected: serde_json::Value = serde_json::from_str(exp_str).unwrap();
assert!(json_contains(&candidate, &expected));
Expand Down
2 changes: 1 addition & 1 deletion trustchain-core/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ impl From<serde_json::Error> for VerifierError {
}

/// A Unix timestamp.
pub type Timestamp = u32;
pub type Timestamp = u64;

/// A verifiably-timestamped DID.
pub trait VerifiableTimestamp {
Expand Down
4 changes: 2 additions & 2 deletions trustchain-ffi/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use ssi::vc::LinkedDataProofOptions;
use std::{fs, str::FromStr};
use trustchain_core::TRUSTCHAIN_CONFIG;
use trustchain_core::{verifier::Timestamp, TRUSTCHAIN_CONFIG};
use trustchain_ion::{Endpoint, URL};

use crate::mobile::FFIMobileError;
Expand Down Expand Up @@ -65,7 +65,7 @@ impl Default for EndpointOptions {
#[serde(rename_all = "camelCase")]
pub struct TrustchainOptions {
pub signature_only: bool,
pub root_event_time: u32,
pub root_event_time: Timestamp,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
Expand Down
22 changes: 22 additions & 0 deletions trustchain-http/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use trustchain_core::{
commitment::CommitmentError, issuer::IssuerError, resolver::ResolverError, vc::CredentialError,
verifier::VerifierError, vp::PresentationError,
};
use trustchain_ion::root::TrustchainRootError;

// TODO: refine and add doc comments for error variants
#[derive(Error, Debug)]
Expand All @@ -20,6 +21,8 @@ pub enum TrustchainHTTPError {
ResolverError(ResolverError),
#[error("Trustchain issuer error: {0}")]
IssuerError(IssuerError),
#[error("Trustchain root error: {0}")]
RootError(TrustchainRootError),
#[error("Trustchain presentation error: {0}")]
PresentationError(PresentationError),
#[error("Credential does not exist.")]
Expand Down Expand Up @@ -55,12 +58,19 @@ impl From<VerifierError> for TrustchainHTTPError {
TrustchainHTTPError::VerifierError(err)
}
}

impl From<IssuerError> for TrustchainHTTPError {
fn from(err: IssuerError) -> Self {
TrustchainHTTPError::IssuerError(err)
}
}

impl From<TrustchainRootError> for TrustchainHTTPError {
fn from(err: TrustchainRootError) -> Self {
TrustchainHTTPError::RootError(err)
}
}

impl From<PresentationError> for TrustchainHTTPError {
fn from(err: PresentationError) -> Self {
TrustchainHTTPError::PresentationError(err)
Expand Down Expand Up @@ -108,6 +118,18 @@ impl IntoResponse for TrustchainHTTPError {
err @ TrustchainHTTPError::NoCredentialIssuer => {
(StatusCode::BAD_REQUEST, err.to_string())
}
ref err @ TrustchainHTTPError::RootError(ref variant) => match variant {
TrustchainRootError::NoUniqueRootEvent(_) => {
(StatusCode::BAD_REQUEST, err.to_string())
}
TrustchainRootError::InvalidDate(_, _, _) => {
(StatusCode::BAD_REQUEST, err.to_string())
}
TrustchainRootError::FailedToParseBlockHeight(_) => {
(StatusCode::BAD_REQUEST, err.to_string())
}
_ => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()),
},
err @ TrustchainHTTPError::FailedToVerifyCredential => {
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
}
Expand Down
Loading

0 comments on commit 5088333

Please sign in to comment.