diff --git a/CHANGELOG.md b/CHANGELOG.md index 84419b0e8..af005bbac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow JWT VC without subject id ([#346](https://github.com/spruceid/ssi/pull/#346)). - Add Blockchain Vocabulary v1 2021 context ([#347](https://github.com/spruceid/ssi/pull/#347)). - Construct API URLs for known Tezos test networks ([#350](https://github.com/spruceid/ssi/pull/#350)). +- Add Verifiable Driver's License Vocabulary context file ([#361](https://github.com/spruceid/ssi/pull/361)). ### Changed - Use Error types in bbs code ([#338](https://github.com/spruceid/ssi/pull/#338)). diff --git a/Cargo.toml b/Cargo.toml index afd58070e..2d615c3f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,7 @@ ecdsa = "0.11.1" digest = "0.9" k256 = { version = "0.8", optional = true, features = ["zeroize", "ecdsa"] } p256 = { version = "0.8", optional = true, features = ["zeroize", "ecdsa"] } -ssi-contexts = { version = "0.1.0", path = "contexts/" } +ssi-contexts = { version = "0.1.2", path = "contexts/" } ripemd160 = { version = "0.9", optional = true } sshkeys = "0.3" reqwest = { version = "0.11", features = ["json"] } @@ -111,3 +111,7 @@ uuid = { version = "0.8", features = ["v4", "serde"] } difference = "2.0" did-method-key = { path = "./did-key" } tokio = { version = "1.0", features = ["macros"] } + +[package.metadata.docs.rs] +features = ["secp256r1", "secp256k1", "ripemd-160", "http-did"] +rustdoc-args = ["--cfg", "docsrs"] diff --git a/contexts/Cargo.toml b/contexts/Cargo.toml index 7f76f210a..27d2ee851 100644 --- a/contexts/Cargo.toml +++ b/contexts/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ssi-contexts" -version = "0.1.1" +version = "0.1.2" authors = ["Spruce Systems, Inc."] edition = "2018" license = "Apache-2.0 AND W3C-20150513 AND CC-BY-SA-3.0" diff --git a/contexts/README.md b/contexts/README.md index 83626ce2f..da6886b6c 100644 --- a/contexts/README.md +++ b/contexts/README.md @@ -7,6 +7,10 @@ [Decentralized Identifiers]: https://www.w3.org/TR/did-core/ [Linked Data Proofs]: https://w3c-ccg.github.io/ld-proofs/ +## Updating + +Sometimes context files change over time. This crate aims to keep up to date with upstream changes in the context files it contains. To manually re-fetch the context files, run the script [update.sh](./update.sh) in the source directory. + ## Licenses The licenses of the context files are summarized in the following table. For more details, see the [LICENSES.md](./LICENSES.md) file. diff --git a/contexts/schema.org.jsonld b/contexts/schema.org.jsonld index a232ea981..239438bbe 100644 --- a/contexts/schema.org.jsonld +++ b/contexts/schema.org.jsonld @@ -44,6 +44,7 @@ "AlbumRelease": {"@id": "schema:AlbumRelease"}, "AlignmentObject": {"@id": "schema:AlignmentObject"}, "AllWheelDriveConfiguration": {"@id": "schema:AllWheelDriveConfiguration"}, + "AllergiesHealthAspect": {"@id": "schema:AllergiesHealthAspect"}, "AllocateAction": {"@id": "schema:AllocateAction"}, "AmpStory": {"@id": "schema:AmpStory"}, "AmusementPark": {"@id": "schema:AmusementPark"}, @@ -75,9 +76,9 @@ "Attorney": {"@id": "schema:Attorney"}, "Audience": {"@id": "schema:Audience"}, "AudioObject": {"@id": "schema:AudioObject"}, + "AudioObjectSnapshot": {"@id": "schema:AudioObjectSnapshot"}, "Audiobook": {"@id": "schema:Audiobook"}, "AudiobookFormat": {"@id": "schema:AudiobookFormat"}, - "AuthenticContent": {"@id": "schema:AuthenticContent"}, "AuthoritativeLegalValue": {"@id": "schema:AuthoritativeLegalValue"}, "AuthorizeAction": {"@id": "schema:AuthorizeAction"}, "AutoBodyShop": {"@id": "schema:AutoBodyShop"}, @@ -89,6 +90,7 @@ "AutomatedTeller": {"@id": "schema:AutomatedTeller"}, "AutomotiveBusiness": {"@id": "schema:AutomotiveBusiness"}, "Ayurvedic": {"@id": "schema:Ayurvedic"}, + "BackOrder": {"@id": "schema:BackOrder"}, "BackgroundNewsArticle": {"@id": "schema:BackgroundNewsArticle"}, "Bacteria": {"@id": "schema:Bacteria"}, "Bakery": {"@id": "schema:Bakery"}, @@ -106,6 +108,7 @@ "BefriendAction": {"@id": "schema:BefriendAction"}, "BenefitsHealthAspect": {"@id": "schema:BenefitsHealthAspect"}, "BikeStore": {"@id": "schema:BikeStore"}, + "BioChemEntity": {"@id": "schema:BioChemEntity"}, "Blog": {"@id": "schema:Blog"}, "BlogPosting": {"@id": "schema:BlogPosting"}, "BloodTest": {"@id": "schema:BloodTest"}, @@ -113,6 +116,20 @@ "BoatReservation": {"@id": "schema:BoatReservation"}, "BoatTerminal": {"@id": "schema:BoatTerminal"}, "BoatTrip": {"@id": "schema:BoatTrip"}, + "BodyMeasurementArm": {"@id": "schema:BodyMeasurementArm"}, + "BodyMeasurementBust": {"@id": "schema:BodyMeasurementBust"}, + "BodyMeasurementChest": {"@id": "schema:BodyMeasurementChest"}, + "BodyMeasurementFoot": {"@id": "schema:BodyMeasurementFoot"}, + "BodyMeasurementHand": {"@id": "schema:BodyMeasurementHand"}, + "BodyMeasurementHead": {"@id": "schema:BodyMeasurementHead"}, + "BodyMeasurementHeight": {"@id": "schema:BodyMeasurementHeight"}, + "BodyMeasurementHips": {"@id": "schema:BodyMeasurementHips"}, + "BodyMeasurementInsideLeg": {"@id": "schema:BodyMeasurementInsideLeg"}, + "BodyMeasurementNeck": {"@id": "schema:BodyMeasurementNeck"}, + "BodyMeasurementTypeEnumeration": {"@id": "schema:BodyMeasurementTypeEnumeration"}, + "BodyMeasurementUnderbust": {"@id": "schema:BodyMeasurementUnderbust"}, + "BodyMeasurementWaist": {"@id": "schema:BodyMeasurementWaist"}, + "BodyMeasurementWeight": {"@id": "schema:BodyMeasurementWeight"}, "BodyOfWater": {"@id": "schema:BodyOfWater"}, "Bone": {"@id": "schema:Bone"}, "Book": {"@id": "schema:Book"}, @@ -173,6 +190,7 @@ "CheckInAction": {"@id": "schema:CheckInAction"}, "CheckOutAction": {"@id": "schema:CheckOutAction"}, "CheckoutPage": {"@id": "schema:CheckoutPage"}, + "ChemicalSubstance": {"@id": "schema:ChemicalSubstance"}, "ChildCare": {"@id": "schema:ChildCare"}, "ChildrensEvent": {"@id": "schema:ChildrensEvent"}, "Chiropractic": {"@id": "schema:Chiropractic"}, @@ -260,6 +278,7 @@ "DayOfWeek": {"@id": "schema:DayOfWeek"}, "DaySpa": {"@id": "schema:DaySpa"}, "DeactivateAction": {"@id": "schema:DeactivateAction"}, + "DecontextualizedContent": {"@id": "schema:DecontextualizedContent"}, "DefenceEstablishment": {"@id": "schema:DefenceEstablishment"}, "DefinedRegion": {"@id": "schema:DefinedRegion"}, "DefinedTerm": {"@id": "schema:DefinedTerm"}, @@ -335,11 +354,13 @@ "EUEnergyEfficiencyEnumeration": {"@id": "schema:EUEnergyEfficiencyEnumeration"}, "Ear": {"@id": "schema:Ear"}, "EatAction": {"@id": "schema:EatAction"}, + "EditedOrCroppedContent": {"@id": "schema:EditedOrCroppedContent"}, "EducationEvent": {"@id": "schema:EducationEvent"}, "EducationalAudience": {"@id": "schema:EducationalAudience"}, "EducationalOccupationalCredential": {"@id": "schema:EducationalOccupationalCredential"}, "EducationalOccupationalProgram": {"@id": "schema:EducationalOccupationalProgram"}, "EducationalOrganization": {"@id": "schema:EducationalOrganization"}, + "EffectivenessHealthAspect": {"@id": "schema:EffectivenessHealthAspect"}, "Electrician": {"@id": "schema:Electrician"}, "ElectronicsStore": {"@id": "schema:ElectronicsStore"}, "ElementarySchool": {"@id": "schema:ElementarySchool"}, @@ -416,6 +437,7 @@ "FoodEvent": {"@id": "schema:FoodEvent"}, "FoodService": {"@id": "schema:FoodService"}, "FourWheelDriveConfiguration": {"@id": "schema:FourWheelDriveConfiguration"}, + "FreeReturn": {"@id": "schema:FreeReturn"}, "Friday": {"@id": "schema:Friday"}, "FrontWheelDriveConfiguration": {"@id": "schema:FrontWheelDriveConfiguration"}, "FullRefund": {"@id": "schema:FullRefund"}, @@ -432,6 +454,7 @@ "Gastroenterologic": {"@id": "schema:Gastroenterologic"}, "GatedResidenceCommunity": {"@id": "schema:GatedResidenceCommunity"}, "GenderType": {"@id": "schema:GenderType"}, + "Gene": {"@id": "schema:Gene"}, "GeneralContractor": {"@id": "schema:GeneralContractor"}, "Genetic": {"@id": "schema:Genetic"}, "Genitourinary": {"@id": "schema:Genitourinary"}, @@ -440,6 +463,7 @@ "GeoShape": {"@id": "schema:GeoShape"}, "GeospatialGeometry": {"@id": "schema:GeospatialGeometry"}, "Geriatric": {"@id": "schema:Geriatric"}, + "GettingAccessHealthAspect": {"@id": "schema:GettingAccessHealthAspect"}, "GiveAction": {"@id": "schema:GiveAction"}, "GlutenFreeDiet": {"@id": "schema:GlutenFreeDiet"}, "GolfCourse": {"@id": "schema:GolfCourse"}, @@ -486,6 +510,7 @@ "HotelRoom": {"@id": "schema:HotelRoom"}, "House": {"@id": "schema:House"}, "HousePainter": {"@id": "schema:HousePainter"}, + "HowItWorksHealthAspect": {"@id": "schema:HowItWorksHealthAspect"}, "HowOrWhereHealthAspect": {"@id": "schema:HowOrWhereHealthAspect"}, "HowTo": {"@id": "schema:HowTo"}, "HowToDirection": {"@id": "schema:HowToDirection"}, @@ -501,6 +526,7 @@ "IgnoreAction": {"@id": "schema:IgnoreAction"}, "ImageGallery": {"@id": "schema:ImageGallery"}, "ImageObject": {"@id": "schema:ImageObject"}, + "ImageObjectSnapshot": {"@id": "schema:ImageObjectSnapshot"}, "ImagingTest": {"@id": "schema:ImagingTest"}, "InForce": {"@id": "schema:InForce"}, "InStock": {"@id": "schema:InStock"}, @@ -510,6 +536,7 @@ "InfectiousAgentClass": {"@id": "schema:InfectiousAgentClass"}, "InfectiousDisease": {"@id": "schema:InfectiousDisease"}, "InformAction": {"@id": "schema:InformAction"}, + "IngredientsHealthAspect": {"@id": "schema:IngredientsHealthAspect"}, "InsertAction": {"@id": "schema:InsertAction"}, "InstallAction": {"@id": "schema:InstallAction"}, "Installment": {"@id": "schema:Installment"}, @@ -596,10 +623,12 @@ "MathSolver": {"@id": "schema:MathSolver"}, "MaximumDoseSchedule": {"@id": "schema:MaximumDoseSchedule"}, "MayTreatHealthAspect": {"@id": "schema:MayTreatHealthAspect"}, + "MeasurementTypeEnumeration": {"@id": "schema:MeasurementTypeEnumeration"}, "MediaGallery": {"@id": "schema:MediaGallery"}, "MediaManipulationRatingEnumeration": {"@id": "schema:MediaManipulationRatingEnumeration"}, "MediaObject": {"@id": "schema:MediaObject"}, "MediaReview": {"@id": "schema:MediaReview"}, + "MediaReviewItem": {"@id": "schema:MediaReviewItem"}, "MediaSubscription": {"@id": "schema:MediaSubscription"}, "MedicalAudience": {"@id": "schema:MedicalAudience"}, "MedicalAudienceType": {"@id": "schema:MedicalAudienceType"}, @@ -654,6 +683,7 @@ "MerchantReturnFiniteReturnWindow": {"@id": "schema:MerchantReturnFiniteReturnWindow"}, "MerchantReturnNotPermitted": {"@id": "schema:MerchantReturnNotPermitted"}, "MerchantReturnPolicy": {"@id": "schema:MerchantReturnPolicy"}, + "MerchantReturnPolicySeasonalOverride": {"@id": "schema:MerchantReturnPolicySeasonalOverride"}, "MerchantReturnUnlimitedWindow": {"@id": "schema:MerchantReturnUnlimitedWindow"}, "MerchantReturnUnspecified": {"@id": "schema:MerchantReturnUnspecified"}, "Message": {"@id": "schema:Message"}, @@ -661,11 +691,11 @@ "Midwifery": {"@id": "schema:Midwifery"}, "MinimumAdvertisedPrice": {"@id": "schema:MinimumAdvertisedPrice"}, "MisconceptionsHealthAspect": {"@id": "schema:MisconceptionsHealthAspect"}, - "MissingContext": {"@id": "schema:MissingContext"}, "MixedEventAttendanceMode": {"@id": "schema:MixedEventAttendanceMode"}, "MixtapeAlbum": {"@id": "schema:MixtapeAlbum"}, "MobileApplication": {"@id": "schema:MobileApplication"}, "MobilePhoneStore": {"@id": "schema:MobilePhoneStore"}, + "MolecularEntity": {"@id": "schema:MolecularEntity"}, "Monday": {"@id": "schema:Monday"}, "MonetaryAmount": {"@id": "schema:MonetaryAmount"}, "MonetaryAmountDistribution": {"@id": "schema:MonetaryAmountDistribution"}, @@ -772,6 +802,7 @@ "Obstetric": {"@id": "schema:Obstetric"}, "Occupation": {"@id": "schema:Occupation"}, "OccupationalActivity": {"@id": "schema:OccupationalActivity"}, + "OccupationalExperienceRequirements": {"@id": "schema:OccupationalExperienceRequirements"}, "OccupationalTherapy": {"@id": "schema:OccupationalTherapy"}, "OceanBodyOfWater": {"@id": "schema:OceanBodyOfWater"}, "Offer": {"@id": "schema:Offer"}, @@ -813,6 +844,7 @@ "Organization": {"@id": "schema:Organization"}, "OrganizationRole": {"@id": "schema:OrganizationRole"}, "OrganizeAction": {"@id": "schema:OrganizeAction"}, + "OriginalMediaContent": {"@id": "schema:OriginalMediaContent"}, "OriginalShippingFees": {"@id": "schema:OriginalShippingFees"}, "Osteopathic": {"@id": "schema:Osteopathic"}, "Otolaryngologic": {"@id": "schema:Otolaryngologic"}, @@ -894,6 +926,7 @@ "PreOrder": {"@id": "schema:PreOrder"}, "PreOrderAction": {"@id": "schema:PreOrderAction"}, "PreSale": {"@id": "schema:PreSale"}, + "PregnancyHealthAspect": {"@id": "schema:PregnancyHealthAspect"}, "PrependAction": {"@id": "schema:PrependAction"}, "Preschool": {"@id": "schema:Preschool"}, "PrescriptionOnly": {"@id": "schema:PrescriptionOnly"}, @@ -924,6 +957,7 @@ "Property": {"@id": "schema:Property"}, "PropertyValue": {"@id": "schema:PropertyValue"}, "PropertyValueSpecification": {"@id": "schema:PropertyValueSpecification"}, + "Protein": {"@id": "schema:Protein"}, "Protozoa": {"@id": "schema:Protozoa"}, "Psychiatric": {"@id": "schema:Psychiatric"}, "PsychologicalTreatment": {"@id": "schema:PsychologicalTreatment"}, @@ -986,6 +1020,7 @@ "Report": {"@id": "schema:Report"}, "ReportageNewsArticle": {"@id": "schema:ReportageNewsArticle"}, "ReportedDoseSchedule": {"@id": "schema:ReportedDoseSchedule"}, + "ResearchOrganization": {"@id": "schema:ResearchOrganization"}, "ResearchProject": {"@id": "schema:ResearchProject"}, "Researcher": {"@id": "schema:Researcher"}, "Reservation": {"@id": "schema:Reservation"}, @@ -1008,7 +1043,16 @@ "ResumeAction": {"@id": "schema:ResumeAction"}, "Retail": {"@id": "schema:Retail"}, "ReturnAction": {"@id": "schema:ReturnAction"}, + "ReturnAtKiosk": {"@id": "schema:ReturnAtKiosk"}, + "ReturnByMail": {"@id": "schema:ReturnByMail"}, + "ReturnFeesCustomerResponsibility": {"@id": "schema:ReturnFeesCustomerResponsibility"}, "ReturnFeesEnumeration": {"@id": "schema:ReturnFeesEnumeration"}, + "ReturnInStore": {"@id": "schema:ReturnInStore"}, + "ReturnLabelCustomerResponsibility": {"@id": "schema:ReturnLabelCustomerResponsibility"}, + "ReturnLabelDownloadAndPrint": {"@id": "schema:ReturnLabelDownloadAndPrint"}, + "ReturnLabelInBox": {"@id": "schema:ReturnLabelInBox"}, + "ReturnLabelSourceEnumeration": {"@id": "schema:ReturnLabelSourceEnumeration"}, + "ReturnMethodEnumeration": {"@id": "schema:ReturnMethodEnumeration"}, "ReturnShippingFees": {"@id": "schema:ReturnShippingFees"}, "Review": {"@id": "schema:Review"}, "ReviewAction": {"@id": "schema:ReviewAction"}, @@ -1026,8 +1070,10 @@ "RsvpResponseType": {"@id": "schema:RsvpResponseType"}, "RsvpResponseYes": {"@id": "schema:RsvpResponseYes"}, "SRP": {"@id": "schema:SRP"}, + "SafetyHealthAspect": {"@id": "schema:SafetyHealthAspect"}, "SaleEvent": {"@id": "schema:SaleEvent"}, "SalePrice": {"@id": "schema:SalePrice"}, + "SatireOrParodyContent": {"@id": "schema:SatireOrParodyContent"}, "SatiricalArticle": {"@id": "schema:SatiricalArticle"}, "Saturday": {"@id": "schema:Saturday"}, "Schedule": {"@id": "schema:Schedule"}, @@ -1067,6 +1113,11 @@ "SinglePlayer": {"@id": "schema:SinglePlayer"}, "SingleRelease": {"@id": "schema:SingleRelease"}, "SiteNavigationElement": {"@id": "schema:SiteNavigationElement"}, + "SizeGroupEnumeration": {"@id": "schema:SizeGroupEnumeration"}, + "SizeSpecification": {"@id": "schema:SizeSpecification"}, + "SizeSystemEnumeration": {"@id": "schema:SizeSystemEnumeration"}, + "SizeSystemImperial": {"@id": "schema:SizeSystemImperial"}, + "SizeSystemMetric": {"@id": "schema:SizeSystemMetric"}, "SkiResort": {"@id": "schema:SkiResort"}, "Skin": {"@id": "schema:Skin"}, "SocialEvent": {"@id": "schema:SocialEvent"}, @@ -1090,8 +1141,10 @@ "SportsTeam": {"@id": "schema:SportsTeam"}, "SpreadsheetDigitalDocument": {"@id": "schema:SpreadsheetDigitalDocument"}, "StadiumOrArena": {"@id": "schema:StadiumOrArena"}, + "StagedContent": {"@id": "schema:StagedContent"}, "StagesHealthAspect": {"@id": "schema:StagesHealthAspect"}, "State": {"@id": "schema:State"}, + "Statement": {"@id": "schema:Statement"}, "StatisticalPopulation": {"@id": "schema:StatisticalPopulation"}, "StatusEnumeration": {"@id": "schema:StatusEnumeration"}, "SteeringPositionValue": {"@id": "schema:SteeringPositionValue"}, @@ -1126,6 +1179,7 @@ "TaxiService": {"@id": "schema:TaxiService"}, "TaxiStand": {"@id": "schema:TaxiStand"}, "TaxiVehicleUsage": {"@id": "schema:TaxiVehicleUsage"}, + "Taxon": {"@id": "schema:Taxon"}, "TechArticle": {"@id": "schema:TechArticle"}, "TelevisionChannel": {"@id": "schema:TelevisionChannel"}, "TelevisionStation": {"@id": "schema:TelevisionStation"}, @@ -1160,6 +1214,7 @@ "TrainStation": {"@id": "schema:TrainStation"}, "TrainTrip": {"@id": "schema:TrainTrip"}, "TransferAction": {"@id": "schema:TransferAction"}, + "TransformedContent": {"@id": "schema:TransformedContent"}, "TransitMap": {"@id": "schema:TransitMap"}, "TravelAction": {"@id": "schema:TravelAction"}, "TravelAgency": {"@id": "schema:TravelAgency"}, @@ -1209,6 +1264,7 @@ "VideoGameClip": {"@id": "schema:VideoGameClip"}, "VideoGameSeries": {"@id": "schema:VideoGameSeries"}, "VideoObject": {"@id": "schema:VideoObject"}, + "VideoObjectSnapshot": {"@id": "schema:VideoObjectSnapshot"}, "ViewAction": {"@id": "schema:ViewAction"}, "VinylFormat": {"@id": "schema:VinylFormat"}, "VirtualLocation": {"@id": "schema:VirtualLocation"}, @@ -1228,6 +1284,52 @@ "WatchAction": {"@id": "schema:WatchAction"}, "Waterfall": {"@id": "schema:Waterfall"}, "WearAction": {"@id": "schema:WearAction"}, + "WearableMeasurementBack": {"@id": "schema:WearableMeasurementBack"}, + "WearableMeasurementChestOrBust": {"@id": "schema:WearableMeasurementChestOrBust"}, + "WearableMeasurementCollar": {"@id": "schema:WearableMeasurementCollar"}, + "WearableMeasurementCup": {"@id": "schema:WearableMeasurementCup"}, + "WearableMeasurementHeight": {"@id": "schema:WearableMeasurementHeight"}, + "WearableMeasurementHips": {"@id": "schema:WearableMeasurementHips"}, + "WearableMeasurementInseam": {"@id": "schema:WearableMeasurementInseam"}, + "WearableMeasurementLength": {"@id": "schema:WearableMeasurementLength"}, + "WearableMeasurementOutsideLeg": {"@id": "schema:WearableMeasurementOutsideLeg"}, + "WearableMeasurementSleeve": {"@id": "schema:WearableMeasurementSleeve"}, + "WearableMeasurementTypeEnumeration": {"@id": "schema:WearableMeasurementTypeEnumeration"}, + "WearableMeasurementWaist": {"@id": "schema:WearableMeasurementWaist"}, + "WearableMeasurementWidth": {"@id": "schema:WearableMeasurementWidth"}, + "WearableSizeGroupBig": {"@id": "schema:WearableSizeGroupBig"}, + "WearableSizeGroupBoys": {"@id": "schema:WearableSizeGroupBoys"}, + "WearableSizeGroupEnumeration": {"@id": "schema:WearableSizeGroupEnumeration"}, + "WearableSizeGroupExtraShort": {"@id": "schema:WearableSizeGroupExtraShort"}, + "WearableSizeGroupExtraTall": {"@id": "schema:WearableSizeGroupExtraTall"}, + "WearableSizeGroupGirls": {"@id": "schema:WearableSizeGroupGirls"}, + "WearableSizeGroupHusky": {"@id": "schema:WearableSizeGroupHusky"}, + "WearableSizeGroupInfants": {"@id": "schema:WearableSizeGroupInfants"}, + "WearableSizeGroupJuniors": {"@id": "schema:WearableSizeGroupJuniors"}, + "WearableSizeGroupMaternity": {"@id": "schema:WearableSizeGroupMaternity"}, + "WearableSizeGroupMens": {"@id": "schema:WearableSizeGroupMens"}, + "WearableSizeGroupMisses": {"@id": "schema:WearableSizeGroupMisses"}, + "WearableSizeGroupPetite": {"@id": "schema:WearableSizeGroupPetite"}, + "WearableSizeGroupPlus": {"@id": "schema:WearableSizeGroupPlus"}, + "WearableSizeGroupRegular": {"@id": "schema:WearableSizeGroupRegular"}, + "WearableSizeGroupShort": {"@id": "schema:WearableSizeGroupShort"}, + "WearableSizeGroupTall": {"@id": "schema:WearableSizeGroupTall"}, + "WearableSizeGroupWomens": {"@id": "schema:WearableSizeGroupWomens"}, + "WearableSizeSystemAU": {"@id": "schema:WearableSizeSystemAU"}, + "WearableSizeSystemBR": {"@id": "schema:WearableSizeSystemBR"}, + "WearableSizeSystemCN": {"@id": "schema:WearableSizeSystemCN"}, + "WearableSizeSystemContinental": {"@id": "schema:WearableSizeSystemContinental"}, + "WearableSizeSystemDE": {"@id": "schema:WearableSizeSystemDE"}, + "WearableSizeSystemEN13402": {"@id": "schema:WearableSizeSystemEN13402"}, + "WearableSizeSystemEnumeration": {"@id": "schema:WearableSizeSystemEnumeration"}, + "WearableSizeSystemEurope": {"@id": "schema:WearableSizeSystemEurope"}, + "WearableSizeSystemFR": {"@id": "schema:WearableSizeSystemFR"}, + "WearableSizeSystemGS1": {"@id": "schema:WearableSizeSystemGS1"}, + "WearableSizeSystemIT": {"@id": "schema:WearableSizeSystemIT"}, + "WearableSizeSystemJP": {"@id": "schema:WearableSizeSystemJP"}, + "WearableSizeSystemMX": {"@id": "schema:WearableSizeSystemMX"}, + "WearableSizeSystemUK": {"@id": "schema:WearableSizeSystemUK"}, + "WearableSizeSystemUS": {"@id": "schema:WearableSizeSystemUS"}, "WebAPI": {"@id": "schema:WebAPI"}, "WebApplication": {"@id": "schema:WebApplication"}, "WebContent": {"@id": "schema:WebContent"}, @@ -1314,6 +1416,7 @@ "alignmentType": { "@id": "schema:alignmentType"}, "alternateName": { "@id": "schema:alternateName"}, "alternativeHeadline": { "@id": "schema:alternativeHeadline"}, + "alternativeOf": { "@id": "schema:alternativeOf"}, "alumni": { "@id": "schema:alumni"}, "alumniOf": { "@id": "schema:alumniOf"}, "amenityFeature": { "@id": "schema:amenityFeature"}, @@ -1337,6 +1440,7 @@ "appliesToDeliveryMethod": { "@id": "schema:appliesToDeliveryMethod"}, "appliesToPaymentMethod": { "@id": "schema:appliesToPaymentMethod"}, "archiveHeld": { "@id": "schema:archiveHeld"}, + "archivedAt": { "@id": "schema:archivedAt", "@type": "@id"}, "area": { "@id": "schema:area"}, "areaServed": { "@id": "schema:areaServed"}, "arrivalAirport": { "@id": "schema:arrivalAirport"}, @@ -1361,8 +1465,12 @@ "assesses": { "@id": "schema:assesses"}, "associatedAnatomy": { "@id": "schema:associatedAnatomy"}, "associatedArticle": { "@id": "schema:associatedArticle"}, + "associatedClaimReview": { "@id": "schema:associatedClaimReview"}, + "associatedDisease": { "@id": "schema:associatedDisease", "@type": "@id"}, "associatedMedia": { "@id": "schema:associatedMedia"}, + "associatedMediaReview": { "@id": "schema:associatedMediaReview"}, "associatedPathophysiology": { "@id": "schema:associatedPathophysiology"}, + "associatedReview": { "@id": "schema:associatedReview"}, "athlete": { "@id": "schema:athlete"}, "attendee": { "@id": "schema:attendee"}, "attendees": { "@id": "schema:attendees"}, @@ -1403,6 +1511,9 @@ "billingIncrement": { "@id": "schema:billingIncrement"}, "billingPeriod": { "@id": "schema:billingPeriod"}, "billingStart": { "@id": "schema:billingStart"}, + "bioChemInteraction": { "@id": "schema:bioChemInteraction"}, + "bioChemSimilarity": { "@id": "schema:bioChemSimilarity"}, + "biologicalRole": { "@id": "schema:biologicalRole"}, "biomechnicalClass": { "@id": "schema:biomechnicalClass"}, "birthDate": { "@id": "schema:birthDate", "@type": "Date"}, "birthPlace": { "@id": "schema:birthPlace"}, @@ -1469,12 +1580,16 @@ "cheatCode": { "@id": "schema:cheatCode"}, "checkinTime": { "@id": "schema:checkinTime"}, "checkoutTime": { "@id": "schema:checkoutTime"}, + "chemicalComposition": { "@id": "schema:chemicalComposition"}, + "chemicalRole": { "@id": "schema:chemicalRole"}, "childMaxAge": { "@id": "schema:childMaxAge"}, "childMinAge": { "@id": "schema:childMinAge"}, + "childTaxon": { "@id": "schema:childTaxon"}, "children": { "@id": "schema:children"}, "cholesterolContent": { "@id": "schema:cholesterolContent"}, "circle": { "@id": "schema:circle"}, "citation": { "@id": "schema:citation"}, + "claimInterpreter": { "@id": "schema:claimInterpreter"}, "claimReviewed": { "@id": "schema:claimReviewed"}, "clincalPharmacology": { "@id": "schema:clincalPharmacology"}, "clinicalPharmacology": { "@id": "schema:clinicalPharmacology"}, @@ -1534,6 +1649,8 @@ "costPerUnit": { "@id": "schema:costPerUnit"}, "countriesNotSupported": { "@id": "schema:countriesNotSupported"}, "countriesSupported": { "@id": "schema:countriesSupported"}, + "countryOfAssembly": { "@id": "schema:countryOfAssembly"}, + "countryOfLastProcessing": { "@id": "schema:countryOfLastProcessing"}, "countryOfOrigin": { "@id": "schema:countryOfOrigin"}, "course": { "@id": "schema:course"}, "courseCode": { "@id": "schema:courseCode"}, @@ -1552,6 +1669,9 @@ "currency": { "@id": "schema:currency"}, "currentExchangeRate": { "@id": "schema:currentExchangeRate"}, "customer": { "@id": "schema:customer"}, + "customerRemorseReturnFees": { "@id": "schema:customerRemorseReturnFees"}, + "customerRemorseReturnLabelSource": { "@id": "schema:customerRemorseReturnLabelSource"}, + "customerRemorseReturnShippingFeesAmount": { "@id": "schema:customerRemorseReturnShippingFeesAmount"}, "cutoffTime": { "@id": "schema:cutoffTime"}, "cvdCollectionDate": { "@id": "schema:cvdCollectionDate"}, "cvdFacilityCounty": { "@id": "schema:cvdFacilityCounty"}, @@ -1610,6 +1730,7 @@ "diet": { "@id": "schema:diet"}, "dietFeatures": { "@id": "schema:dietFeatures"}, "differentialDiagnosis": { "@id": "schema:differentialDiagnosis"}, + "directApply": { "@id": "schema:directApply"}, "director": { "@id": "schema:director"}, "directors": { "@id": "schema:directors"}, "disambiguatingDescription": { "@id": "schema:disambiguatingDescription"}, @@ -1671,12 +1792,14 @@ "eligibleTransactionVolume": { "@id": "schema:eligibleTransactionVolume"}, "email": { "@id": "schema:email"}, "embedUrl": { "@id": "schema:embedUrl", "@type": "@id"}, + "embeddedTextCaption": { "@id": "schema:embeddedTextCaption"}, "emissionsCO2": { "@id": "schema:emissionsCO2"}, "employee": { "@id": "schema:employee"}, "employees": { "@id": "schema:employees"}, "employerOverview": { "@id": "schema:employerOverview"}, "employmentType": { "@id": "schema:employmentType"}, "employmentUnit": { "@id": "schema:employmentUnit"}, + "encodesBioChemEntity": { "@id": "schema:encodesBioChemEntity"}, "encodesCreativeWork": { "@id": "schema:encodesCreativeWork"}, "encoding": { "@id": "schema:encoding"}, "encodingFormat": { "@id": "schema:encodingFormat"}, @@ -1724,9 +1847,11 @@ "expectedArrivalUntil": { "@id": "schema:expectedArrivalUntil", "@type": "Date"}, "expectedPrognosis": { "@id": "schema:expectedPrognosis"}, "expectsAcceptanceOf": { "@id": "schema:expectsAcceptanceOf"}, + "experienceInPlaceOfEducation": { "@id": "schema:experienceInPlaceOfEducation"}, "experienceRequirements": { "@id": "schema:experienceRequirements"}, "expertConsiderations": { "@id": "schema:expertConsiderations"}, "expires": { "@id": "schema:expires", "@type": "Date"}, + "expressedIn": { "@id": "schema:expressedIn"}, "familyName": { "@id": "schema:familyName"}, "fatContent": { "@id": "schema:fatContent"}, "faxNumber": { "@id": "schema:faxNumber"}, @@ -1803,6 +1928,8 @@ "guidelineDate": { "@id": "schema:guidelineDate", "@type": "Date"}, "guidelineSubject": { "@id": "schema:guidelineSubject"}, "handlingTime": { "@id": "schema:handlingTime"}, + "hasBioChemEntityPart": { "@id": "schema:hasBioChemEntityPart"}, + "hasBioPolymerSequence": { "@id": "schema:hasBioPolymerSequence"}, "hasBroadcastChannel": { "@id": "schema:hasBroadcastChannel"}, "hasCategoryCode": { "@id": "schema:hasCategoryCode"}, "hasCourse": { "@id": "schema:hasCourse"}, @@ -1816,15 +1943,18 @@ "hasEnergyEfficiencyCategory": { "@id": "schema:hasEnergyEfficiencyCategory"}, "hasHealthAspect": { "@id": "schema:hasHealthAspect"}, "hasMap": { "@id": "schema:hasMap", "@type": "@id"}, + "hasMeasurement": { "@id": "schema:hasMeasurement"}, "hasMenu": { "@id": "schema:hasMenu"}, "hasMenuItem": { "@id": "schema:hasMenuItem"}, "hasMenuSection": { "@id": "schema:hasMenuSection"}, "hasMerchantReturnPolicy": { "@id": "schema:hasMerchantReturnPolicy"}, + "hasMolecularFunction": { "@id": "schema:hasMolecularFunction", "@type": "@id"}, "hasOccupation": { "@id": "schema:hasOccupation"}, "hasOfferCatalog": { "@id": "schema:hasOfferCatalog"}, "hasPOS": { "@id": "schema:hasPOS"}, "hasPart": { "@id": "schema:hasPart"}, "hasProductReturnPolicy": { "@id": "schema:hasProductReturnPolicy"}, + "hasRepresentation": { "@id": "schema:hasRepresentation"}, "hasVariant": { "@id": "schema:hasVariant"}, "headline": { "@id": "schema:headline"}, "healthCondition": { "@id": "schema:healthCondition"}, @@ -1864,6 +1994,8 @@ "imagingTechnique": { "@id": "schema:imagingTechnique"}, "inAlbum": { "@id": "schema:inAlbum"}, "inBroadcastLineup": { "@id": "schema:inBroadcastLineup"}, + "inChI": { "@id": "schema:inChI"}, + "inChIKey": { "@id": "schema:inChIKey"}, "inCodeSet": { "@id": "schema:inCodeSet", "@type": "@id"}, "inDefinedTermSet": { "@id": "schema:inDefinedTermSet", "@type": "@id"}, "inLanguage": { "@id": "schema:inLanguage"}, @@ -1901,6 +2033,7 @@ "interactionType": { "@id": "schema:interactionType"}, "interactivityType": { "@id": "schema:interactivityType"}, "interestRate": { "@id": "schema:interestRate"}, + "interpretedAsClaim": { "@id": "schema:interpretedAsClaim"}, "inventoryLevel": { "@id": "schema:inventoryLevel"}, "inverseOf": { "@id": "schema:inverseOf"}, "isAcceptingNewPatients": { "@id": "schema:isAcceptingNewPatients"}, @@ -1910,10 +2043,14 @@ "isBasedOn": { "@id": "schema:isBasedOn", "@type": "@id"}, "isBasedOnUrl": { "@id": "schema:isBasedOnUrl", "@type": "@id"}, "isConsumableFor": { "@id": "schema:isConsumableFor"}, + "isEncodedByBioChemEntity": { "@id": "schema:isEncodedByBioChemEntity"}, "isFamilyFriendly": { "@id": "schema:isFamilyFriendly"}, "isGift": { "@id": "schema:isGift"}, + "isInvolvedInBiologicalProcess": { "@id": "schema:isInvolvedInBiologicalProcess", "@type": "@id"}, "isLiveBroadcast": { "@id": "schema:isLiveBroadcast"}, + "isLocatedInSubcellularLocation": { "@id": "schema:isLocatedInSubcellularLocation", "@type": "@id"}, "isPartOf": { "@id": "schema:isPartOf", "@type": "@id"}, + "isPartOfBioChemEntity": { "@id": "schema:isPartOfBioChemEntity"}, "isPlanForApartment": { "@id": "schema:isPlanForApartment"}, "isProprietary": { "@id": "schema:isProprietary"}, "isRelatedTo": { "@id": "schema:isRelatedTo"}, @@ -1931,6 +2068,9 @@ "iswcCode": { "@id": "schema:iswcCode"}, "item": { "@id": "schema:item"}, "itemCondition": { "@id": "schema:itemCondition"}, + "itemDefectReturnFees": { "@id": "schema:itemDefectReturnFees"}, + "itemDefectReturnLabelSource": { "@id": "schema:itemDefectReturnLabelSource"}, + "itemDefectReturnShippingFeesAmount": { "@id": "schema:itemDefectReturnShippingFeesAmount"}, "itemListElement": { "@id": "schema:itemListElement"}, "itemListOrder": { "@id": "schema:itemListOrder"}, "itemLocation": { "@id": "schema:itemLocation"}, @@ -1938,6 +2078,7 @@ "itemReviewed": { "@id": "schema:itemReviewed"}, "itemShipped": { "@id": "schema:itemShipped"}, "itinerary": { "@id": "schema:itinerary"}, + "iupacName": { "@id": "schema:iupacName"}, "jobBenefits": { "@id": "schema:jobBenefits"}, "jobImmediateStart": { "@id": "schema:jobImmediateStart"}, "jobLocation": { "@id": "schema:jobLocation"}, @@ -2025,6 +2166,7 @@ "measurementTechnique": { "@id": "schema:measurementTechnique"}, "mechanismOfAction": { "@id": "schema:mechanismOfAction"}, "mediaAuthenticityCategory": { "@id": "schema:mediaAuthenticityCategory"}, + "mediaItemAppearance": { "@id": "schema:mediaItemAppearance"}, "median": { "@id": "schema:median"}, "medicalAudience": { "@id": "schema:medicalAudience"}, "medicalSpecialty": { "@id": "schema:medicalSpecialty"}, @@ -2040,7 +2182,7 @@ "menu": { "@id": "schema:menu"}, "menuAddOn": { "@id": "schema:menuAddOn"}, "merchant": { "@id": "schema:merchant"}, - "merchantReturnDays": { "@id": "schema:merchantReturnDays"}, + "merchantReturnDays": { "@id": "schema:merchantReturnDays", "@type": "Date"}, "merchantReturnLink": { "@id": "schema:merchantReturnLink", "@type": "@id"}, "messageAttachment": { "@id": "schema:messageAttachment"}, "mileageFromOdometer": { "@id": "schema:mileageFromOdometer"}, @@ -2051,7 +2193,11 @@ "model": { "@id": "schema:model"}, "modelDate": { "@id": "schema:modelDate", "@type": "Date"}, "modifiedTime": { "@id": "schema:modifiedTime"}, + "molecularFormula": { "@id": "schema:molecularFormula"}, + "molecularWeight": { "@id": "schema:molecularWeight"}, + "monoisotopicMolecularWeight": { "@id": "schema:monoisotopicMolecularWeight"}, "monthlyMinimumRepaymentAmount": { "@id": "schema:monthlyMinimumRepaymentAmount"}, + "monthsOfExperience": { "@id": "schema:monthsOfExperience"}, "mpn": { "@id": "schema:mpn"}, "multipleValues": { "@id": "schema:multipleValues"}, "muscleAction": { "@id": "schema:muscleAction"}, @@ -2066,6 +2212,7 @@ "namedPosition": { "@id": "schema:namedPosition"}, "nationality": { "@id": "schema:nationality"}, "naturalProgression": { "@id": "schema:naturalProgression"}, + "negativeNotes": { "@id": "schema:negativeNotes"}, "nerve": { "@id": "schema:nerve"}, "nerveMotor": { "@id": "schema:nerveMotor"}, "netWorth": { "@id": "schema:netWorth"}, @@ -2131,6 +2278,8 @@ "orderedItem": { "@id": "schema:orderedItem"}, "organizer": { "@id": "schema:organizer"}, "originAddress": { "@id": "schema:originAddress"}, + "originalMediaContextDescription": { "@id": "schema:originalMediaContextDescription"}, + "originalMediaLink": { "@id": "schema:originalMediaLink", "@type": "@id"}, "originatesFrom": { "@id": "schema:originatesFrom"}, "overdosage": { "@id": "schema:overdosage"}, "ownedFrom": { "@id": "schema:ownedFrom"}, @@ -2144,6 +2293,7 @@ "parentItem": { "@id": "schema:parentItem"}, "parentOrganization": { "@id": "schema:parentOrganization"}, "parentService": { "@id": "schema:parentService"}, + "parentTaxon": { "@id": "schema:parentTaxon"}, "parents": { "@id": "schema:parents"}, "partOfEpisode": { "@id": "schema:partOfEpisode"}, "partOfInvoice": { "@id": "schema:partOfInvoice"}, @@ -2194,6 +2344,7 @@ "polygon": { "@id": "schema:polygon"}, "populationType": { "@id": "schema:populationType"}, "position": { "@id": "schema:position"}, + "positiveNotes": { "@id": "schema:positiveNotes"}, "possibleComplication": { "@id": "schema:possibleComplication"}, "possibleTreatment": { "@id": "schema:possibleTreatment"}, "postOfficeBoxNumber": { "@id": "schema:postOfficeBoxNumber"}, @@ -2204,6 +2355,7 @@ "postalCodePrefix": { "@id": "schema:postalCodePrefix"}, "postalCodeRange": { "@id": "schema:postalCodeRange"}, "potentialAction": { "@id": "schema:potentialAction"}, + "potentialUse": { "@id": "schema:potentialUse"}, "preOp": { "@id": "schema:preOp"}, "predecessorOf": { "@id": "schema:predecessorOf"}, "pregnancyCategory": { "@id": "schema:pregnancyCategory"}, @@ -2335,11 +2487,17 @@ "reservedTicket": { "@id": "schema:reservedTicket"}, "responsibilities": { "@id": "schema:responsibilities"}, "restPeriods": { "@id": "schema:restPeriods"}, + "restockingFee": { "@id": "schema:restockingFee"}, "result": { "@id": "schema:result"}, "resultComment": { "@id": "schema:resultComment"}, "resultReview": { "@id": "schema:resultReview"}, "returnFees": { "@id": "schema:returnFees"}, + "returnLabelSource": { "@id": "schema:returnLabelSource"}, + "returnMethod": { "@id": "schema:returnMethod"}, "returnPolicyCategory": { "@id": "schema:returnPolicyCategory"}, + "returnPolicyCountry": { "@id": "schema:returnPolicyCountry"}, + "returnPolicySeasonalOverride": { "@id": "schema:returnPolicySeasonalOverride"}, + "returnShippingFeesAmount": { "@id": "schema:returnShippingFeesAmount"}, "review": { "@id": "schema:review"}, "reviewAspect": { "@id": "schema:reviewAspect"}, "reviewBody": { "@id": "schema:reviewBody"}, @@ -2403,6 +2561,7 @@ "serviceType": { "@id": "schema:serviceType"}, "serviceUrl": { "@id": "schema:serviceUrl", "@type": "@id"}, "servingSize": { "@id": "schema:servingSize"}, + "sha256": { "@id": "schema:sha256"}, "sharedContent": { "@id": "schema:sharedContent"}, "shippingDestination": { "@id": "schema:shippingDestination"}, "shippingDetails": { "@id": "schema:shippingDetails"}, @@ -2417,9 +2576,12 @@ "significantLink": { "@id": "schema:significantLink", "@type": "@id"}, "significantLinks": { "@id": "schema:significantLinks", "@type": "@id"}, "size": { "@id": "schema:size"}, + "sizeGroup": { "@id": "schema:sizeGroup"}, + "sizeSystem": { "@id": "schema:sizeSystem"}, "skills": { "@id": "schema:skills"}, "sku": { "@id": "schema:sku"}, "slogan": { "@id": "schema:slogan"}, + "smiles": { "@id": "schema:smiles"}, "smokingAllowed": { "@id": "schema:smokingAllowed"}, "sodiumContent": { "@id": "schema:sodiumContent"}, "softwareAddOn": { "@id": "schema:softwareAddOn"}, @@ -2476,9 +2638,11 @@ "subtitleLanguage": { "@id": "schema:subtitleLanguage"}, "successorOf": { "@id": "schema:successorOf"}, "sugarContent": { "@id": "schema:sugarContent"}, + "suggestedAge": { "@id": "schema:suggestedAge"}, "suggestedAnswer": { "@id": "schema:suggestedAnswer"}, "suggestedGender": { "@id": "schema:suggestedGender"}, "suggestedMaxAge": { "@id": "schema:suggestedMaxAge"}, + "suggestedMeasurement": { "@id": "schema:suggestedMeasurement"}, "suggestedMinAge": { "@id": "schema:suggestedMinAge"}, "suitableForDiet": { "@id": "schema:suitableForDiet"}, "superEvent": { "@id": "schema:superEvent"}, @@ -2496,6 +2660,8 @@ "targetProduct": { "@id": "schema:targetProduct"}, "targetUrl": { "@id": "schema:targetUrl", "@type": "@id"}, "taxID": { "@id": "schema:taxID"}, + "taxonRank": { "@id": "schema:taxonRank"}, + "taxonomicRange": { "@id": "schema:taxonomicRange"}, "teaches": { "@id": "schema:teaches"}, "telephone": { "@id": "schema:telephone"}, "temporal": { "@id": "schema:temporal"}, diff --git a/contexts/src/lib.rs b/contexts/src/lib.rs index 4eda204a1..650bbeb35 100644 --- a/contexts/src/lib.rs +++ b/contexts/src/lib.rs @@ -1,3 +1,5 @@ +// Note: update ../update.sh when updating URLs/filenames in this file. + /// pub const CREDENTIALS_V1: &str = include_str!("../w3c-2018-credentials-v1.jsonld"); /// diff --git a/contexts/update.sh b/contexts/update.sh new file mode 100755 index 000000000..0c744da7a --- /dev/null +++ b/contexts/update.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# Note: update src/lib.rs when updating URLs/filenames in this file. +cd "$(dirname "$0")" || exit 1 +exec curl \ + https://www.w3.org/2018/credentials/v1 -o w3c-2018-credentials-v1.jsonld \ + https://www.w3.org/2018/credentials/examples/v1 -o w3c-2018-credentials-examples-v1.jsonld \ + https://www.w3.org/ns/odrl.jsonld -o w3c-odrl.jsonld \ + https://schema.org/docs/jsonldcontext.jsonld -o schema.org.jsonld \ + https://w3id.org/security/v1 -o w3id-security-v1.jsonld \ + https://w3id.org/security/v2 -o w3id-security-v2.jsonld \ + https://www.w3.org/ns/did/v1 -o w3c-did-v1.jsonld \ + https://w3id.org/did-resolution/v1 -o w3c-did-resolution-v1.jsonld \ + https://identity.foundation/EcdsaSecp256k1RecoverySignature2020/lds-ecdsa-secp256k1-recovery2020-0.0.jsonld -o dif-lds-ecdsa-secp256k1-recovery2020-0.0.jsonld \ + https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json -o lds-jws2020-v1.jsonld \ + https://w3id.org/security/suites/jws-2020/v1 -o w3id-jws2020-v1.jsonld \ + https://w3id.org/security/suites/ed25519-2020/v1 -o w3id-ed25519-signature-2020-v1.jsonld \ + https://w3id.org/security/suites/blockchain-2021/v1 -o w3id-blockchain-2021-v1.jsonld \ + https://w3id.org/citizenship/v1 -o w3c-ccg-citizenship-v1.jsonld \ + https://w3id.org/vaccination/v1 -o w3c-ccg-vaccination-v1.jsonld \ + https://w3id.org/traceability/v1 -o w3c-ccg-traceability-v1.jsonld \ + https://demo.spruceid.com/EcdsaSecp256k1RecoverySignature2020/esrs2020-extra-0.0.jsonld -o esrs2020-extra-0.0.jsonld \ + https://w3id.org/security/bbs/v1 -o bbs-v1.jsonld \ + https://identity.foundation/presentation-exchange/submission/v1 -o presentation-submission.jsonld \ + https://w3id.org/vdl/v1 -o w3id-vdl-v1.jsonld \ + -L diff --git a/contexts/w3c-2018-credentials-examples-v1.jsonld b/contexts/w3c-2018-credentials-examples-v1.jsonld index b2d2295e2..173626c76 100644 --- a/contexts/w3c-2018-credentials-examples-v1.jsonld +++ b/contexts/w3c-2018-credentials-examples-v1.jsonld @@ -18,6 +18,9 @@ "Mother": "ex:Mother", "RelationshipCredential": "ex:RelationshipCredential", "UniversityDegreeCredential": "ex:UniversityDegreeCredential", + "AlumniCredential": "ex:AlumniCredential", + "DisputeCredential": "ex:DisputeCredential", + "PrescriptionCredential": "ex:PrescriptionCredential", "ZkpExampleSchema2018": "ex:ZkpExampleSchema2018", "issuerData": "ex:issuerData", @@ -42,6 +45,9 @@ "evidenceDocument": "ex:evidenceDocument", "spouse": "schema:spouse", "subjectPresence": "ex:subjectPresence", - "verifier": {"@id": "ex:verifier", "@type": "@id"} + "verifier": {"@id": "ex:verifier", "@type": "@id"}, + "currentStatus": "ex:currentStatus", + "statusReason": "ex:statusReason", + "prescription": "ex:prescription" }] } diff --git a/contexts/w3c-ccg-traceability-v1.jsonld b/contexts/w3c-ccg-traceability-v1.jsonld index 191652998..799a32220 100644 --- a/contexts/w3c-ccg-traceability-v1.jsonld +++ b/contexts/w3c-ccg-traceability-v1.jsonld @@ -1,6 +1,7 @@ { "@context": { "@version": 1.1, + "@vocab": "https://w3id.org/traceability/#undefinedTerm", "id": "@id", "type": "@type", "name": "https://schema.org/name", @@ -46,7 +47,7 @@ "@id": "https://www.gs1.org/voc/Place" }, "inspector": { - "@id": "https://w3id.org/traceability?v1#Inspector" + "@id": "https://w3id.org/traceability#Inspector" }, "shipment": { "@id": "https://schema.org/ParcelDelivery" @@ -161,9 +162,30 @@ "billOfLadingNumber": { "@id": "https://schema.org/identifier" }, + "bookingNumber": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncl1153/#Consignment_identifier_carrier_assigned" + }, "relatedDocuments": { "@id": "https://schema.org/Purchase" }, + "scac": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncl1153/#Standard_Carrier_Alpha_Code_(SCAC)_number" + }, + "carrier": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#carrierParty" + }, + "consignor": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#consignorParty" + }, + "consignee": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#consigneeParty" + }, + "notify": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#notifyParty" + }, + "freightForwarder": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#freightForwarderParty" + }, "freight": { "@id": "https://schema.org/ParcelDelivery" }, @@ -172,6 +194,9 @@ }, "hazardCode": { "@id": "https://w3id.org/traceability#hazardCode" + }, + "placeOfIssue": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncl3227/#Place_of_discharge" } } }, @@ -190,23 +215,119 @@ } } }, + "CTPATCertificate": { + "@id": "https://w3id.org/traceability#CTPATCertificate", + "@context": { + "ctpatCertifiedEntity": { + "@id": "https://w3id.org/traceability#ctpatCertifiedEntity" + } + } + }, + "CargoItem": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#ConsignmentItem", + "@context": { + "cargoLineItems": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/cargoLineItem" + }, + "carrierBookingReference": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#carrierAssignedId" + }, + "weight": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#netWeightMeasure" + }, + "chargeableWeight": { + "@id": "https://schema.org/weight" + }, + "volume": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#grossVolumeMeasure" + }, + "weightUnit": { + "@id": "https://schema.org/unitCode" + }, + "volumeUnit": { + "@id": "https://schema.org/unitCode" + }, + "grossWeightUnit": { + "@id": "https://schema.org/unitCode" + }, + "numberOfPackages": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#packageQuantity" + }, + "numberOfPieces": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#packageQuantity" + }, + "name": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#tradeLineItemQuantity" + }, + "packageCode": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#packageTypeCode" + }, + "grossWeight": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#grossWeightMeasure" + }, + "rateClass": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#freightChargeTariffClassCode" + }, + "commodityItemNumber": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#discountIndicator" + }, + "rateCharge": { + "@id": "https://schema.org/price" + }, + "total": { + "@id": "https://schema.org/totalPrice" + }, + "natureAndVolumeOfGoods": { + "@id": "https://schema.org/description" + }, + "manufacturer": { + "@id": "https://schema.org/Organization" + }, + "orderNumber": { + "@id": "https://schema.org/orderNumber" + }, + "transportPackage": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#Package" + } + } + }, + "CargoLineItem": { + "@id": "https://w3id.org/traceability#CargoLineItem", + "@context": { + "cargoLineItemID": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/cargoLineItemID" + }, + "shippingMarks": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#physicalShippingMarks" + }, + "descriptionOfGoods": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/descriptionOfGoods" + }, + "HSCode": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/HSCode" + } + } + }, "ChargeDeclaration": { "@id": "https://w3id.org/traceability#ChargeDeclaration", "@context": { "weightCharge": { - "@id": "https://schema.org/PriceSpecification" + "@id": "https://schema.org/price" }, - "taxCharge": { + "valuationCharge": { "@id": "https://schema.org/price" }, - "otherChargesAgent": { - "@id": "https://schema.org/totalPrice" + "tax": { + "@id": "https://schema.org/price" }, - "otherChargesCarrier": { - "@id": "https://schema.org/discountPrice" + "dueAgent": { + "@id": "https://schema.org/price" }, - "totalCharge": { - "@id": "https://w3id.org/traceability#TotalCharge" + "dueCarrier": { + "@id": "https://schema.org/price" + }, + "total": { + "@id": "https://schema.org/totalPrice" } } }, @@ -266,6 +387,20 @@ "@id": "https://w3id.org/traceability#CommercialInvoiceCertificate", "@context": {} }, + "Commodity": { + "@id": "https://w3id.org/traceability#Commodity", + "@context": { + "commodityCode": { + "@id": "https://w3id.org/traceability#commodityCode" + }, + "commodityCodeType": { + "@id": "https://w3id.org/traceability#commodityCodeType" + }, + "description": { + "@id": "https://schema.org/description" + } + } + }, "ContactPoint": { "@id": "https://schema.org/ContactPoint", "@context": { @@ -293,13 +428,13 @@ "@id": "https://www.gs1.org/voc/Place" }, "UWI": { - "@id": "https://schema.org/identifier?1" + "@id": "https://schema.org/identifier" }, "HSCode": { - "@id": "https://w3id.org/identifier?2" + "@id": "https://w3id.org/identifier" }, "productionDate": { - "@id": "https://schema.org/DateTime#v2" + "@id": "https://schema.org/DateTime" }, "observation": { "@id": "https://w3id.org/traceability#observation" @@ -323,6 +458,115 @@ } } }, + "DCSAShippingInstruction": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#Instructions", + "@context": { + "shippingInstructionID": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncl1153/#Transport_instruction_number" + }, + "transportDocumentType": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/transportDocumentType" + }, + "preCarriageUnderShippersResponsibility": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/preCarriageUnderShippersResponsibility" + }, + "invoicePayableAt": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/invoicePayableAt" + }, + "carrierBookingReference": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncl1153/#Consignment_identifier_carrier_assigned" + }, + "cargoItems": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#includedConsignmentItem" + }, + "utilizedTransportEquipments": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#utilizedTransportEquipment" + }, + "shipmentLocations": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DOCUMENTATION_DOMAIN/1.0.0#/components/schemas/shipmentLocation" + }, + "shipper": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#consignorParty" + }, + "consignee": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#consigneeParty" + }, + "invoicePayerConsignee": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#consigneeParty" + }, + "invoicePayerShipper": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#shipperParty" + }, + "notify": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#notifyParty" + }, + "shippersFreightForwarder": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#freightForwarderParty" + }, + "consigneesFreightForwarder": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#freightForwarderParty" + } + } + }, + "DCSATransportDocument": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/transportDocument", + "@context": { + "transportDocumentReference": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncl1153/#Bill_of_lading_number" + }, + "placeOfIssue": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#issueLocation" + }, + "issueDate": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#issueDateTime" + }, + "shippedOnBoardDate": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.2#/components/schemas/shippedOnBoardDate" + }, + "receivedForShipmentDate": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#availabilityDueDateTime" + }, + "termsAndConditions": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#termsAndConditionsDescription" + }, + "issuerCode": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncl1153/#Standard_Carrier_Alpha_Code_(SCAC)_number" + }, + "issuerCodeListProvider": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.2#/components/schemas/issuerCodeListProvider" + }, + "declaredValueCurrency": { + "@id": "https://schema.org/currency" + }, + "cargoMovementTypeAtOrigin": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.2#/components/schemas/cargoMovementTypeAtOrigin" + }, + "cargoMovementTypeAtDestination": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.2#/components/schemas/cargoMovementTypeAtDestination" + }, + "receiptDeliveryTypeAtOrigin": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.2#/components/schemas/receiptDeliveryTypeAtOrigin" + }, + "receiptDeliveryTypeAtDestination": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.2#/components/schemas/receiptDeliveryTypeAtDestination" + }, + "serviceContractReference": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.2#/components/schemas/serviceContractReference" + }, + "shippingInstruction": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/shippingInstruction" + }, + "charges": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/charges" + }, + "clauses": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/clauses" + }, + "transports": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/transports" + } + } + }, "DocumentVerificationEvidence": { "@id": "https://w3id.org/traceability#DocumentVerificationEvidence", "@context": { @@ -524,35 +768,6 @@ } } }, - "EcommercePackageRegistrationEvidenceDocument": { - "@id": "https://w3id.org/traceability#EcommercePackageRegistrationEvidenceDocument", - "@context": { - "deliveryStatus": { - "@id": "https://schema.org/deliveryStatus" - }, - "expectedArrivalFrom": { - "@id": "https://schema.org/expectedArrivalFrom" - }, - "hasDeliveryMethod": { - "@id": "https://schema.org/hasDeliveryMethod" - }, - "deliveryAddress": { - "@id": "https://schema.org/deliveryAddress" - }, - "provider": { - "@id": "https://schema.org/provider" - }, - "originAddress": { - "@id": "https://schema.org/originAddress" - }, - "trackingNumber": { - "@id": "https://schema.org/trackingNumber" - }, - "partOfOrder": { - "@id": "https://schema.org/partOfOrder" - } - } - }, "EcommercePackingListItem": { "@id": "https://w3id.org/traceability#EcommercePackingListItem", "@context": { @@ -575,32 +790,6 @@ } } }, - "EcommercePackingListRegistrationEvidenceDocument": { - "@id": "https://w3id.org/traceability#EcommercePackingListRegistrationEvidenceDocument", - "@context": { - "deliveryStatus": { - "@id": "https://schema.org/deliveryStatus" - }, - "expectedArrivalFrom": { - "@id": "https://schema.org/expectedArrivalFrom" - }, - "hasDeliveryMethod": { - "@id": "https://schema.org/hasDeliveryMethod" - }, - "deliveryAddress": { - "@id": "https://schema.org/deliveryAddress" - }, - "provider": { - "@id": "https://schema.org/provider" - }, - "originAddress": { - "@id": "https://schema.org/originAddress" - }, - "partOfOrder": { - "@id": "https://schema.org/partOfOrder" - } - } - }, "EcommerceProductReceiptRegistrationCredential": { "@id": "https://w3id.org/traceability#EcommerceProductReceiptRegistrationCredential", "@context": { @@ -635,31 +824,6 @@ } } }, - "EcommerceWayBillCommodityContent": { - "@id": "https://w3id.org/traceability#EcommerceWayBillCommodityContent", - "@context": { - "wayBillGrouping": { - "@id": "https://w3id.org/traceability#EcommerceWayBillCommodityGroup" - }, - "totalsCommodityContent": { - "@id": "https://w3id.org/traceability#EcommerceWayBillTotals" - } - } - }, - "EcommerceWayBillCommodityGroup": { - "@id": "https://w3id.org/traceability#EcommerceWayBillCommodityGroup", - "@context": { - "commodityItemNumber": { - "@id": "https://schema.org/identifier" - }, - "natureQuantityOfGoods": { - "@id": "https://schema.org/description" - }, - "totalsCommodityGroup": { - "@id": "https://w3id.org/traceability#EcommerceWayBillTotals" - } - } - }, "EcommerceWayBillRegistrationCredential": { "@id": "https://w3id.org/traceability#EcommerceWayBillRegistrationCredential", "@context": { @@ -689,111 +853,186 @@ } } }, - "EcommerceWayBillRegistrationEvidenceDocument": { - "@id": "https://w3id.org/traceability#EcommerceWayBillRegistrationEvidenceDocument", + "Entity": { + "@id": "https://w3id.org/traceability#Entity", + "@context": {} + }, + "Event": { + "@id": "https://schema.org/Event", "@context": { - "issuanceDate": { - "@id": "https://schema.org/dateIssued" + "eventType": { + "@id": "https://schema.org/value" + }, + "eventId": { + "@id": "https://schema.org/identifier" + }, + "actor": { + "@id": "https://w3id.org/traceability#Organization" + }, + "place": { + "@id": "https://w3id.org/traceability#place" + }, + "eventTime": { + "@id": "https://schema.org/DateTime" + }, + "products": { + "@id": "https://schema.org/Product" + } + } + }, + "ForeignChargeDeclaration": { + "@id": "https://w3id.org/traceability#ForeignChargeDeclaration", + "@context": { + "foreignCurrencyConvertionRate": { + "@id": "https://schema.org/currentExchangeRate" + }, + "foreignChargesCurrency": { + "@id": "https://schema.org/currency" }, - "waybillNumber": { + "foreignCharges": { + "@id": "https://schema.org/price" + } + } + }, + "GeoCoordinates": { + "@id": "https://schema.org/GeoCoordinates", + "@context": { + "latitude": { + "@id": "https://schema.org/latitude" + }, + "longitude": { + "@id": "https://schema.org/longitude" + } + } + }, + "IATAAirWaybillCertificate": { + "@id": "https://w3id.org/traceability#IATAAirWaybillCertificate", + "@context": { + "airWaybillNumber": { "@id": "https://schema.org/orderNumber" }, "waybillType": { "@id": "https://schema.org/DigitalDocument" }, - "issuer": { - "@id": "https://schema.org/Organization" + "airlineCodeNumber": { + "@id": "https://onerecord.iata.org/cargo/Company#airlineCode" + }, + "destinationAirport": { + "@id": "https://onerecord.iata.org/cargo/Company#airlineCode" + }, + "serialNumber": { + "@id": "https://schema.org/serialNumber" + }, + "airportOfDeparture": { + "@id": "https://onerecord.iata.org/cargo/Location#code" + }, + "carrier": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#carrierParty" + }, + "conditionsOfContract": { + "@id": "https://schema.org/termsOfService" }, "shipper": { - "@id": "https://schema.org/broker" + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#consignorParty" }, - "sidNumber": { + "shippersAccountNumber": { + "@id": "https://schema.org/accountId" + }, + "consigneesAccountNumber": { + "@id": "https://schema.org/accountId" + }, + "agentAccountNumber": { "@id": "https://schema.org/accountId" }, "consignee": { - "@id": "https://schema.org/Corporation" + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#consigneeParty" }, - "cidNumber": { - "@id": "https://schema.org/identifier" + "issuingCarrierAgent": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#carrierAgentParty" }, - "issuerAgent": { - "@id": "https://w3id.org/traceability#IssuerAgent" + "agentIATACode": { + "@id": "https://onerecord.iata.org/cargo/Company#iataCargoAgentCode" }, - "shippingRoute": { + "requestedRouting": { "@id": "https://schema.org/Trip" }, - "handlingInstructions": { - "@id": "https://schema.org/description" + "requestedFlight": { + "@id": "https://schema.org/Flight" + }, + "requestedDate": { + "@id": "https://schema.org/Date" + }, + "executedOn": { + "@id": "https://schema.org/Date" + }, + "accountingInformation": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#typeCode" + }, + "currency": { + "@id": "https://schema.org/currency" + }, + "chargeCodes": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#chargeCategoryCode" + }, + "weightValuationChargesType": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#chargeCategoryCode" + }, + "otherChargesType": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#chargeCategoryCode" + }, + "declaredValueForCarriage": { + "@id": "https://schema.org/value" + }, + "amountOfInsurance": { + "@id": "https://schema.org/value" + }, + "declaredValueForCustoms": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#customsValueSpecifiedAmount" + }, + "insuranceClauses": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#contractualClause" }, - "handlingInstructionsSCI": { - "@id": "https://schema.org/Code" + "handlingInformation": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#handlingInstructions" }, - "wayBillCommodityContent": { - "@id": "https://w3id.org/traceability#EcommerceWayBillCommodityContent" + "specialCustomsInformation": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#Declaration" }, - "chargeDeclaration": { - "@id": "https://w3id.org/traceability#ChargeDeclaration" - } - } - }, - "EcommerceWayBillTotals": { - "@id": "https://w3id.org/traceability#EcommerceWayBillTotals", - "@context": { - "totalPieces": { - "@id": "https://schema.org/Number" + "consignmentRatingDetails": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#includedConsignmentItem" }, - "weight": { - "@id": "https://schema.org/weight" + "totalNumberOfPieces": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#packageQuantity" }, - "chargeableWeight": { - "@id": "https://schema.org/QuantitativeValue" + "totalGrossWeight": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#grossWeightMeasure" }, - "weightUnit": { - "@id": "https://schema.org/unitCode" + "totalCharge": { + "@id": "https://schema.org/totalPrice" }, - "rateCharge": { - "@id": "https://schema.org/Price" + "prepaidTotal": { + "@id": "https://schema.org/totalPrice" }, - "totalRateCharge": { + "collectTotal": { "@id": "https://schema.org/totalPrice" - } - } - }, - "Entity": { - "@id": "https://w3id.org/traceability#Entity", - "@context": {} - }, - "Event": { - "@id": "https://schema.org/Event", - "@context": { - "eventType": { - "@id": "https://schema.org/value" }, - "eventId": { - "@id": "https://schema.org/identifier" + "otherCharges": { + "@id": "https://schema.org/price" }, - "actor": { - "@id": "https://w3id.org/traceability#Organization" + "prepaidChargeDeclaration": { + "@id": "https://w3id.org/traceability#PrepaidChargeDeclaration" }, - "place": { - "@id": "https://w3id.org/traceability#place" + "collectChargeDeclaration": { + "@id": "https://w3id.org/traceability#CollectChargeDeclaration" }, - "eventTime": { - "@id": "https://schema.org/DateTime#v2" + "destinationCollectChargeDeclaration": { + "@id": "https://w3id.org/traceability#DestinationCollectChargeDeclaration" }, - "products": { - "@id": "https://schema.org/Product" - } - } - }, - "GeoCoordinates": { - "@id": "https://schema.org/GeoCoordinates", - "@context": { - "latitude": { - "@id": "https://schema.org/latitude" + "shippersCertificationBox": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#Certification" }, - "longitude": { - "@id": "https://schema.org/longitude" + "executedAt": { + "@id": "https://schema.org/Place" } } }, @@ -807,43 +1046,43 @@ "@id": "https://schema.org/ParcelDelivery" }, "inBondNumber": { - "@id": "https://w3id.org/identifier?1" + "@id": "https://w3id.org/identifier" }, "entryId": { - "@id": "https://w3id.org/identifier?3" + "@id": "https://w3id.org/identifier" }, "ftzNo": { - "@id": "https://w3id.org/identifier?2" + "@id": "https://w3id.org/identifier" }, "inBondType": { - "@id": "https://w3id.org/identifier?6" + "@id": "https://w3id.org/identifier" + }, + "irsNumber": { + "@id": "https://w3id.org/identifier" + }, + "billOfLadingNumber": { + "@id": "https://w3id.org/identifier" }, "portOfEntry": { - "@id": "https://www.gs1.org/voc/Place?3" + "@id": "https://www.gs1.org/voc/Place" }, "portOfDestination": { - "@id": "https://www.gs1.org/voc/Place?4" + "@id": "https://www.gs1.org/voc/Place" }, "portOfArrival": { - "@id": "https://www.gs1.org/voc/Place?5" + "@id": "https://www.gs1.org/voc/Place" }, "carrier": { - "@id": "https://w3id.org/traceability?2#Entity?1" - }, - "irsNumber": { - "@id": "https://w3id.org/identifier?4" + "@id": "https://w3id.org/traceability#Entity" }, "recipient": { - "@id": "https://w3id.org/traceability?2#Entity?2" - }, - "billOfLadingNumber": { - "@id": "https://w3id.org/identifier?5" + "@id": "https://w3id.org/traceability#Entity" }, "expectedDeliveryDate": { - "@id": "https://schema.org/DateTime#v2" + "@id": "https://schema.org/DateTime" }, "valuePerItem": { - "@id": "https://schema.org/PriceSpecification?1" + "@id": "https://schema.org/PriceSpecification" }, "totalOrderValue": { "@id": "https://schema.org/PriceSpecification" @@ -865,7 +1104,7 @@ "@id": "https://w3id.org/traceability#Inspector", "@context": { "person": { - "@id": "https://schema.org/Person.json" + "@id": "https://schema.org/Person" }, "qualification": { "@id": "https://w3id.org/traceability#qualification" @@ -876,19 +1115,19 @@ "@id": "https://w3id.org/traceability#IntentToSell", "@context": { "seller": { - "@id": "https://w3id.org/traceability?1#Entity" + "@id": "https://w3id.org/traceability#Entity" }, "purchaser": { - "@id": "https://w3id.org/traceability?2#Entity" + "@id": "https://w3id.org/traceability#Entity" }, "product": { "@id": "https://www.gs1.org/voc/Product" }, "declarationDate": { - "@id": "https://schema.org/DateTime?v=1" + "@id": "https://schema.org/DateTime" }, "sellByDate": { - "@id": "https://schema.org/DateTime?v=2" + "@id": "https://schema.org/DateTime" } } }, @@ -956,38 +1195,6 @@ } } }, - "ItemShipped": { - "@id": "https://w3id.org/traceability#ItemShipped", - "@context": { - "manufacturer": { - "@id": "https://schema.org/manufacturer" - }, - "name": { - "@id": "https://schema.org/name" - }, - "description": { - "@id": "https://schema.org/description" - }, - "productID": { - "@id": "https://schema.org/productID" - }, - "weight": { - "@id": "https://schema.org/weight" - }, - "height": { - "@id": "https://schema.org/height" - }, - "width": { - "@id": "https://schema.org/width" - }, - "depth": { - "@id": "https://schema.org/depth" - }, - "orderQuantity": { - "@id": "https://schema.org/orderQuantity" - } - } - }, "LEIaddress": { "@id": "https://w3id.org/traceability#LEIaddress", "@context": { @@ -1212,13 +1419,13 @@ "@id": "https://www.gs1.org/voc/Place" }, "UWI": { - "@id": "https://schema.org/identifier?1" + "@id": "https://schema.org/identifier" }, "HSCode": { - "@id": "https://w3id.org/identifier?2" + "@id": "https://w3id.org/identifier" }, "productionDate": { - "@id": "https://schema.org/DateTime#v2" + "@id": "https://schema.org/DateTime" }, "observation": { "@id": "https://w3id.org/traceability#observation" @@ -1232,28 +1439,28 @@ "@id": "https://w3id.org/traceability#BillOfLading" }, "shippingDate": { - "@id": "https://schema.org/DateTime?1" + "@id": "https://schema.org/DateTime" }, "arrivalDate": { - "@id": "https://schema.org/DateTime?2" + "@id": "https://schema.org/DateTime" }, "valuePerItem": { - "@id": "https://www.schema.org/value?1" + "@id": "https://www.schema.org/value" }, "totalOrderValue": { - "@id": "https://www.schema.org/value?2" + "@id": "https://www.schema.org/value" }, "freightChargeTerms": { - "@id": "https://www.schema.org/value?3" + "@id": "https://www.schema.org/value" }, "batchNumber": { "@id": "https://schema.org/identifier" }, "openingVolume": { - "@id": "https://schema.org/MeasuredValue?2" + "@id": "https://schema.org/MeasuredValue" }, "closingVolume": { - "@id": "https://schema.org/MeasuredValue?1" + "@id": "https://schema.org/MeasuredValue" }, "observation": { "@id": "https://w3id.org/traceability#observation" @@ -1329,6 +1536,88 @@ }, "contactPoint": { "@id": "https://schema.org/ContactPoint" + }, + "taxId": { + "@id": "https://schema.org/taxID" + }, + "iataCarrierCode": { + "@id": "https://onerecord.iata.org/cargo/Company#airlineCode" + } + } + }, + "Package": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#Package", + "@context": { + "shippingMarks": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#perPackageUnitQuantity" + }, + "name": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#itemQuantity" + }, + "itemsShipped": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#includedTradeLineItem" + }, + "weight": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#grossWeightMeasure" + }, + "weightUnit": { + "@id": "https://schema.org/unitCode" + }, + "volumeUnit": { + "@id": "https://schema.org/unitCode" + }, + "height": { + "@id": "https://schema.org/height" + }, + "width": { + "@id": "https://schema.org/width" + }, + "depth": { + "@id": "https://schema.org/depth" + }, + "volume": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#grossVolumeMeasure" + } + } + }, + "PackingListCertificate": { + "@id": "https://w3id.org/traceability#PackingListCertificate", + "@context": { + "deliveryStatus": { + "@id": "https://schema.org/deliveryStatus" + }, + "estimatedTimeOfArrival": { + "@id": "https://schema.org/arrivalTime" + }, + "hasDeliveryMethod": { + "@id": "https://schema.org/hasDeliveryMethod" + }, + "deliveryAddress": { + "@id": "https://schema.org/deliveryAddress" + }, + "provider": { + "@id": "https://schema.org/provider" + }, + "originAddress": { + "@id": "https://schema.org/originAddress" + }, + "partOfOrder": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#ConsignmentItem" + }, + "weight": { + "@id": "https://schema.org/weight" + }, + "weightUnit": { + "@id": "https://schema.org/unitCode" + }, + "volumeUnit": { + "@id": "https://schema.org/unitCode" + }, + "volume": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#grossVolumeMeasure" + }, + "numberOfPackages": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#packageQuantity" } } }, @@ -1361,17 +1650,6 @@ } } }, - "PartOfOrder": { - "@id": "https://w3id.org/traceability#PartOfOrder", - "@context": { - "orderNumber": { - "@id": "https://schema.org/orderNumber" - }, - "itemsShipped": { - "@id": "https://schema.org/itemShipped" - } - } - }, "Person": { "@id": "https://schema.org/Person", "@context": { @@ -1392,6 +1670,9 @@ }, "jobTitle": { "@id": "https://schema.org/jobTitle" + }, + "taxId": { + "@id": "https://schema.org/taxID" } } }, @@ -1411,7 +1692,10 @@ "@id": "https://w3id.org/traceability#portOfEntry" }, "additionalDeclaration": { - "@id": "https://schema.org/Comment#v2" + "@id": "https://schema.org/Comment" + }, + "notes": { + "@id": "https://schema.org/Comment" }, "disinfectionDate": { "@id": "https://schema.org/validFrom" @@ -1432,13 +1716,16 @@ "@id": "https://w3id.org/traceability#disinfectionConcentration" }, "signatureDate": { - "@id": "https://schema.org/DateTime#v2" + "@id": "https://schema.org/DateTime" + }, + "inspectionDate": { + "@id": "https://schema.org/DateTime" }, "facility": { "@id": "https://www.gs1.org/voc/Place" }, "inspector": { - "@id": "https://w3id.org/traceability?v3#Inspector" + "@id": "https://w3id.org/traceability#Inspector" }, "shipment": { "@id": "https://schema.org/AgParcelDelivery" @@ -1449,15 +1736,9 @@ "applicant": { "@id": "https://w3c-ccg.github.io/traceability-vocab/#dfn-entities" }, - "inspectionDate": { - "@id": "https://schema.org/DateTime" - }, "inspectionType": { "@id": "https://www.schema.org/value" }, - "notes": { - "@id": "https://schema.org/Comment" - }, "observation": { "@id": "https://schema.org/ItemList" } @@ -1474,6 +1755,9 @@ }, "address": { "@id": "https://schema.org/PostalAddress" + }, + "unLocode": { + "@id": "https://onerecord.iata.org/cargo/Location#code" } } }, @@ -1561,6 +1845,9 @@ }, "sku": { "@id": "https://schema.org/sku" + }, + "commodity": { + "@id": "https://w3id.org/traceability#Commodity" } } }, @@ -1639,7 +1926,7 @@ "@id": "https://w3id.org/traceability#Purchase", "@context": { "customer": { - "@id": "https://w3id.org/traceability#Entity?v4" + "@id": "https://w3id.org/traceability#Entity" }, "invoice": { "@id": "https://w3id.org/traceability#Invoice" @@ -1682,14 +1969,31 @@ } } }, + "Seal": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#Seal", + "@context": { + "equipmentReference": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#seal_number" + }, + "ISOEquipmentCode": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/sealSource" + }, + "tareWeight": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/sealType" + } + } + }, "ShippingStop": { "@id": "https://w3id.org/traceability#ShippingStop", "@context": { - "shippingStopAddress": { - "@id": "https://schema.org/PostalAddress" + "from": { + "@id": "https://schema.org/Place" + }, + "to": { + "@id": "https://schema.org/Place" }, "carrier": { - "@id": "https://schema.org/Organizationn" + "@id": "https://schema.org/Organization" }, "vesselNumber": { "@id": "https://schema.org/identifier" @@ -1709,7 +2013,7 @@ "@id": "https://schema.org/identifier" }, "specification": { - "@id": "https://schema.org/identifier?v=1" + "@id": "https://schema.org/identifier" }, "grade": { "@id": "https://schema.org/Rating" @@ -1731,32 +2035,95 @@ } } }, - "TotalCharge": { - "@id": "https://w3id.org/traceability#TotalCharge", + "TradeLineItem": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#TradeLineItem", "@context": { - "totalPrepaid": { - "@id": "https://schema.org/Price" + "name": { + "@id": "https://schema.org/name" }, - "totalCollect": { - "@id": "https://schema.org/totalPrice" + "description": { + "@id": "https://schema.org/description" }, - "sourceCurrency": { - "@id": "https://schema.org/priceCurrency" + "productID": { + "@id": "https://schema.org/productID" }, - "destinationCurrency": { - "@id": "https://schema.org/currency" + "itemCount": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#despatchedQuantity" + } + } + }, + "Transport": { + "@id": "https://w3id.org/traceability#Transport", + "@context": { + "loadLocation": { + "@id": "https://schema.org/Place" }, - "currencyConversionRate": { - "@id": "https://schema.org/ExchangeRateSpecification" + "dischargeLocation": { + "@id": "https://schema.org/Place" }, - "ccChargesDestinationCurrency": { - "@id": "https://schema.org/discountCurrency" + "plannedDepartureDate": { + "@id": "https://schema.org/Date" }, - "chargesDestination": { - "@id": "https://schema.org/Number" + "plannedArrivalDate": { + "@id": "https://schema.org/Date" + }, + "modeOfTransport": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/modeOfTransport" + }, + "carrier": { + "@id": "https://schema.org/Organization" + }, + "vesselNumber": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#TransportMeans" + }, + "voyageNumber": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#TransportMovement" + } + } + }, + "TransportEquipment": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#TransportEquipment", + "@context": { + "equipmentReference": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#identificationId" + }, + "ISOEquipmentCode": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/ISOEquipmentCode" + }, + "tareWeight": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#grossWeightMeasure" + }, + "weightUnit": { + "@id": "https://api.swaggerhub.com/domains/dcsaorg/DCSA_DOMAIN/1.0.1#/components/schemas/weightUnit" + }, + "isShipperOwned": { + "@id": "https://service.unece.org/trade/uncefact/vocabulary/uncefact/#affixedSeal" + } + } + }, + "USMCACertificateOfOrigin": { + "@id": "https://w3id.org/traceability#USMCACertificateOfOrigin", + "@context": { + "importer": { + "@id": "https://w3id.org/traceability#certifier" + }, + "exporterDetails": { + "@id": "https://w3id.org/traceability#importerUnknown" + }, + "producerDetails": { + "@id": "https://schema.org/manufacturer" + }, + "importerDetails": { + "@id": "https://w3id.org/traceability#importerDetails" + }, + "goods": { + "@id": "https://schema.org/itemShipped" + }, + "blanketPeriodFrom": { + "@id": "https://schema.org/validFrom" }, - "totalCollectCharge": { - "@id": "https://schema.org/estimatedCost" + "blanketPeriodTo": { + "@id": "https://schema.org/validThrough" } } }, @@ -1788,7 +2155,7 @@ "@id": "https://www.gs1.org/voc/Place" }, "inspector": { - "@id": "https://w3id.org/traceability?v2#Inspector" + "@id": "https://w3id.org/traceability#Inspector" }, "shipment": { "@id": "https://w3id.org/traceability#AgParcelDelivery" @@ -1810,17 +2177,21 @@ } } }, - "chargeAndPaymentType": { - "@id": "https://w3id.org/traceability#chargeAndPaymentType", + "usmcaProductSpecifier": { + "@id": "https://w3id.org/traceability/UsmcaProductSpecifier", "@context": { - "chargeCollect": { - "@id": "https://schema.org/discountPrice" + "product": { + "@id": "https://schema.org/Product" }, - "chargePrepaid": { - "@id": "https://schema.org/totalPrice" + "importer": { + "@id": "https://w3id.org/traceability#countryOfOrigin" } } }, + "VerifiableBusinessCard": { + "@id": "https://w3id.org/traceability#VerifiableBusinessCard", + "@context": {} + }, "ppq203": { "@id": "https://w3id.org/traceability#ppq203", "@context": { @@ -1837,7 +2208,7 @@ "@id": "https://www.gs1.org/voc/Place" }, "inspector": { - "@id": "https://w3id.org/traceability?v2#Inspector" + "@id": "https://w3id.org/traceability#Inspector" }, "shipment": { "@id": "https://schema.org/ParcelDelivery" diff --git a/did-ethr/src/lib.rs b/did-ethr/src/lib.rs index 108e36306..8f3b9fc8c 100644 --- a/did-ethr/src/lib.rs +++ b/did-ethr/src/lib.rs @@ -103,7 +103,7 @@ fn resolve_pk( ); } }; - let account_address = match ssi::keccak_hash::hash_public_key(&pk_jwk) { + let account_address = match ssi::keccak_hash::hash_public_key_eip55(&pk_jwk) { Ok(hash) => hash, Err(e) => { return ( diff --git a/did-ethr/tests/did-pk.jsonld b/did-ethr/tests/did-pk.jsonld index 6dfa41e75..604cb7d70 100644 --- a/did-ethr/tests/did-pk.jsonld +++ b/did-ethr/tests/did-pk.jsonld @@ -17,7 +17,7 @@ "id": "did:ethr:0x03fdd57adec3d438ea237fe46b33ee1e016eda6b585c3e27ea66686c2ea5358479#controller", "type": "EcdsaSecp256k1RecoveryMethod2020", "controller": "did:ethr:0x03fdd57adec3d438ea237fe46b33ee1e016eda6b585c3e27ea66686c2ea5358479", - "blockchainAccountId": "eip155:1:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74" + "blockchainAccountId": "eip155:1:0xF3beAC30C498D9E26865F34fCAa57dBB935b0D74" }, { "id": "did:ethr:0x03fdd57adec3d438ea237fe46b33ee1e016eda6b585c3e27ea66686c2ea5358479#controllerKey", diff --git a/did-pkh/did-pkh-method-draft.md b/did-pkh/did-pkh-method-draft.md index 0ef29fbd9..2bf309ec8 100644 --- a/did-pkh/did-pkh-method-draft.md +++ b/did-pkh/did-pkh-method-draft.md @@ -1,256 +1,4 @@ -# did:pkh Method Specification +# did:pkh -Authors: Wayne Chang, Charles Lehner, Juan Caballero -Status: Draft - -## Introduction - -### Problem Statement - -There are over hundreds of billions of on-chain, balance-holding accounts across -the major 50 or so blockchains, all secured and namespaced using similar -technologies. Almost all of these derive identifiers from hashed or otherwise -obscured public keys, which are provided at time of transaction. - -These accounts are used to protect billions of dollars in assets and critical -digital infrastructure. They are also actively being piloted and used by -enterprises and governments. They are rapidly becoming a major form of shared -data infrastructure across verticals and continents. - -DIDs should favor usability where possible, and it is extremely beneficial from -a security & human computer interaction perspective to have DIDs that readily -correspond to their equivalents on decentralized networks. This corresponds -neatly to end-users' understanding of what an "account" is on an existing -network. There are knock-on security effects to having an -immediately-recognizable "address" double as a DID for usage elsewhere. - -It also allows most if not all blockchain accounts to instantly leverage an -existing identity/account and deploy a W3C Decentralized Identifier from it in a -standards-conformant way. This "DID-wrapping" of an existing identifier can be -used in combination with other DID-compatible technologies, such as W3C -Verifiable Credentials or Authorization Capabilities, and produce proper -signature-suite definitions, such as "metamask-signing" (signing according to -the [[eip712]] protocol, soon to be a work item at W3C-CCG). - -### Relationship to other DID architectures - -did:pkh bears many similarities to -[did:key](https://w3c-ccg.github.io/did-method-key/#introduction) except it is -optimized for identifiers derived from hashes of public keys according to -well-known algorithms (commonly referred to as "public key hashes" because in -most cases they are a public key hashed according to a standard hash function). - -### Combination with other DID methods - -Another difference from did:key is that did:pkh is design to have many "upgrade -paths" for DIDs deterministically generated from existing keypairs. Namely: -- if a did:pkh is controlled by a keypair which is valid for generating a - blockchain-published DID document according to another method (for instance, - did:tz, did:btcr or did:ethr), its did document can be translated to the form - of that method's documents, and it can be registered there. - -## Design Goals - -1. The primary goal of this method is to allow any valid blockchain address to - "spin up" a feature-limited but valid and widely interoperable DID and DID - Document, valid in a limited context where accounts are represented by DIDs. -2. This method is very narrow and unopinionated to allow a wide range of - implementations. -3. For example, the validity of each address to be wrapped in a DID is checked - according to the [CAIP-10] standard before generating, to prevent a did:pkh - being presented as valid that would not be on its corresponding blockchain. - **No further validation** is assumed or provided in the reference - implemention, but implementers may still choose to gate generation to - on-chain accounts or balance-holding accounts as per the requirements of - their specific use case. -4. As this method is designed for interoperability with blockchain web wallets, - authentication and signing functions are left to the blockchain-specific - capabilities of the wallets supported by a given implementation, "dApp", or - context. This has implications for the degree of privacy and security that - can be assumed. Importantly, these vary across blockchains so some use-cases - may choose to treat PKHs differently per prefix. - -## Identifier scheme - -### Syntax and Interpretation - -``` -pkh-did = "did:pkh:" address -address = account_address according to [CAIP-10] -``` - -### Examples - -Here is an example from each currently supported network, linked to a sample -JSON-LD DID document derived from each: - -| Network (key type) | example (linked to sample DID document) | -|:---:|:---:| -| btc | [did:pkh:bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-btc.jsonld) | -| doge | [did:pkh:bip122:1a91e3dace36e2be3bf030a65679fe82:DH5yaieqoZN36fDVciNyRueRGvGLR3mr7L](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-doge.jsonld) | -| eth (mainnet) | [did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-eth.jsonld) | -| celo | [did:pkh:eip155:42220:0xa0ae58da58dfa46fa55c3b86545e7065f90ff011](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-celo.jsonld) | -| solana | [did:pkh:solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ:CKg5d12Jhpej1JqtmxLJgaFqqeYjxgPqToJ4LBdvG9Ev](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-sol.jsonld) | -| poly | [did:pkh:eip155:137:0x4e90e8a8191c1c23a24a598c3ab4fb47ce926ff5](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-poly.jsonld) | -| tz (tz1) | [did:pkh:tezos:NetXdQprcVkpaWU:tz1TzrmTBSuiVHV2VfMnGRMYvTEPCP42oSM8](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-tz1.jsonld) | -| tz (tz2) | [did:pkh:tezos:NetXdQprcVkpaWU:tz2BFTyPeYRzxd5aiBchbXN3WCZhx7BqbMBq](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-tz2.jsonld) | -| tz (tz3) | [did:pkh:tezos:NetXdQprcVkpaWU:tz3agP9LGe2cXmKQyYn6T68BHKjjktDbbSWX](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-tz3.jsonld) | - -As you can see, the did:pkh address simply consists of a prefix to identify the -namespace on which the address is valid (and could be published, but isn't -necessarily). Validity is checked according to [CAIP-10][] before -generating. - -### Networks - -Note that networks (i.e., EVMs) and specific chains (i.e., ledgers, including -private DLTs and test-nets) have to be specified separately and explicitly for -all did-pkh addresses; in blockchain systems where accounts are controlled by -multiple keytypes, like Tezos, the network and chain subdomains will not be -enough to identify keytype, which must be detected from the address itself. - -|account type|network id (CAIP-2) + chain id (CAIP-10)|verification method type|URL for context definition| -|---|---|---|---| -|`tz1`|`tezos:NetXdQprcVkpaWU`|Ed25519PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021|https://w3id.org/security#Ed25519PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021| -|`tz`|`tezos:NetXdQprcVkpaWU`|EcdsaSecp256k1RecoveryMethod2020|https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020| -|`tz`|`tezos:NetXdQprcVkpaWU`|P256PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021|https://w3id.org/security#P256PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021| -|ethereum mainnet|`eip155:1`|EcdsaSecp256k1RecoveryMethod2020|https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020| -|celo mainnet|`eip155:42220`|EcdsaSecp256k1RecoveryMethod2020|https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020| -|polygon mainnet|`eip155:137`|EcdsaSecp256k1RecoveryMethod2020|https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020| -|solana|`solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ`|Ed25519VerificationKey2018|https://w3id.org/security#Ed25519VerificationKey2018| -|bitcoin mainnet|`bip122:000000000019d6689c085ae165831e93`|EcdsaSecp256k1RecoveryMethod2020|https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020| -|dogecoin mainnet|`bip122:1a91e3dace36e2be3bf030a65679fe82`|EcdsaSecp256k1RecoveryMethod2020|https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020| - -### Context - -The following should be manually inserted into each DID Document. This will -likely change over time as new verification methods are supported, and -general-purpose methods are specified. Term definitions may be omitted from -these if they are not needed in particular DID documents. - -``` -{ - "blockchainAccountId": "https://w3id.org/security#blockchainAccountId", - "publicKeyJwk": { - "@id": "https://w3id.org/security#publicKeyJwk", - "@type": "@json" - }, - "Ed25519VerificationKey2018": "https://w3id.org/security#Ed25519VerificationKey2018", - "Ed25519PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021": "https://w3id.org/security#Ed25519PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021", - "P256PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021": "https://w3id.org/security#P256PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021", - "TezosMethod2021": "https://w3id.org/security#TezosMethod2021", - "EcdsaSecp256k1RecoveryMethod2020": "https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020" -} -``` -## Operations - -### Create - -The blockchain account id is validated according to [CAIP-10][] and then appended to -`did:pkh:{network}:`, where `{network}` is the supported prefix corresponding to -the blockchain where it is valid. - -### Read (Resolve) - -Resolution implements the following interface defined in [DID Core][]: -``` -resolve(did, resolutionOptions) → - « didResolutionMetadata, didDocument, didDocumentMetadata » -``` - -Construct the DID Document for *did* as follows: -- Parse the DID into its network id, *network* and account address, *address*, - according to Syntax and Interpretation above. -- Initialize a DID document, *doc*, as a JSON-LD document. -- Set the `id` property of *doc* to *did*. -- Set the `@context` property of *doc* to an array, - `["https://www.w3.org/ns/did/v1", context]`, where `context` is the [did:pkh JSON-LD context object](#context). -- Construct the verification method ID, *vm*, by appending - "#blockchainAccountId" to *did*. -- Construct the [verification method][] object, *vmObj* as follows: - - Insert property `id` into *vmObj* with value *vm*. - - Look up network id *network* in the did:pkh [Networks][#networks] table, to - get verification method type *vmType* and [CAIP-2][] chain id *chainId*. If - there are multiple entries in the table for *network*, use one that - matches *address*. - - Insert property `type` into *vmObj* with value *vmType*. - - Insert property `controller` into *vmObj* with value *did*. - - Construct string *accountId* by concatenating *address* + "@" + *chainId*. - - Insert property `blockchainAccountId` into *vmObj* with value *accountId*. -- Insert a property into *doc* with key name `verificationMethod` and a value of - an array containing only *vmObj*. -- Insert a property into *doc* with key name `authentication` and a value of an - array containing only *vm*. -- Insert a property into *doc* with key name `assertionMethod` and value of an - array containing only *vm*. -- Construct an empty DID Resolution metadata object, *resMeta*. -- Construct an empty DID Document metadata object, *docMeta*. -- Return *resMeta*, *doc*, and *docMeta*. - - -### Update - -No updates possible. did:pkh DID Documents are, like [did:key] documents, intended for local-only usage. - -### Delete - -No deletion possible. did:pkh DID Documents are, like [did:key] documents, intended for local-only usage. - -## Security & Privacy Considerations (non-normative) - -There are a number of security and privacy considerations that implementers will want to take into consideration when implementing this specification. These are adapted from the analogous considerations proposed by the did:key authors. - -### Key Rotation Not Supported - -The did:pkh method is a purely generative method, which means that updates are not supported. This can be an issue if a did:pkh is expected to be used over a long period of time. For example, if a did:pkh is ever compromised, it is not possible to rotate the compromised key. For this reason, using a did:pkh for interactions that last weeks to months is strongly discouraged. - -### Deactivation Not Supported - -The did:pkh method is a purely generative method, which means that deactivations and "tombstoning" are not supported internally, and would require a separate system with its own availablity, privacy, and security concerns. This can be an issue if a did:pkh is expected to be used over a long period of time. For example, if a did:pkh is ever compromised, it is not possible to deactivate the DID to stop an attacker from using it. For this reason, using a did:pkh for interactions that last weeks to months is strongly discouraged. - -### Key Derivation Lacks Proof - -Some implementations might utlize a key derivation function when converting from an ed25519 public key to a Curve25519 ECDH key, used in the keyAgreement verification method. It is expected that this is a relatively safe operation, but implementers might consider that there exists no mathematical proof that confirms this assumption. - -### Long Term Usage is Discouraged - -Since there is no support for update and deactivate for the did:pkh method, it is not possible to recover from a security compromise. For this reason, using a did:pkh for interactions that last weeks to months is strongly discouraged. Instead, the recovery, rotation, and in most cases authentication properties of the system from which the PKH originates should be relied on directly. - -## Ref Impl - -|Author|name of implementation|link to pkh libraries|date registered| -|:---:|:---:|:---:|:---:| -|Spruce Systems, USA|[DIDKit](https://github.com/spruceid/didkit/)|`did-pkh` crate in ssi [core library](https://github.com/spruceid/ssi/tree/main/did-pkh)|July 2,2021| - -## Appendix: Legacy Support - -An earlier version of this specification used more human-readable submethod -namespacing rather than referring mapping directly to the CAIP naming -convention. It also defaulted to main-net for `did:pkh:eth` in the absence of an -explicit chainID. As the scope has grown of this project, and with forward -compatibility in mind, both of these patterns have been removed, required -explicitly naming the EVM by its registered [CAIP-2][] code and explicitly -naming the `chain_id` (as specified in [CAIP-10][]) as well. The legacy aliases -that Spruce's implementation also supports for backwards-compatibility with -credentials already issued look like this: - -| prefix | example (linked to sample DID document) | -|:---:|:---:| -| btc | [did:pkh:btc:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-btc-legacy.jsonld) | -| doge | [did:pkh:doge:DH5yaieqoZN36fDVciNyRueRGvGLR3mr7L](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-doge-legacy.jsonld) | -| eth | [did:pkh:eth:0xb9c5714089478a327f09197987f16f9e5d936e8a](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-eth-legacy.jsonld) | -| sol | [did:pkh:sol:CKg5d12Jhpej1JqtmxLJgaFqqeYjxgPqToJ4LBdvG9Ev](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-sol-legacy.jsonld) | -| celo | [did:pkh:celo:0xa0ae58da58dfa46fa55c3b86545e7065f90ff011](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-celo-legacy.jsonld) | -| poly | [did:pkh:poly:0x4e90e8a8191c1c23a24a598c3ab4fb47ce926ff5](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-poly-legacy.jsonld) | -| tz (tz1) | [did:pkh:tz:tz1TzrmTBSuiVHV2VfMnGRMYvTEPCP42oSM8](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-tz1-legacy.jsonld) | -| tz (tz2) | [did:pkh:tz:tz2BFTyPeYRzxd5aiBchbXN3WCZhx7BqbMBq](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-tz2-legacy.jsonld) | -| tz (tz3) | [did:pkh:tz:tz3agP9LGe2cXmKQyYn6T68BHKjjktDbbSWX](https://github.com/spruceid/ssi/blob/main/did-pkh/tests/did-tz3-legacy.jsonld) | - - -[DID Core]: https://www.w3.org/TR/did-core/ -[did:key]: https://w3c-ccg.github.io/did-method-key/ -[verification method]: https://www.w3.org/TR/did-core/#verification-methods -[blockchainaccountid]: https://www.w3.org/TR/did-spec-registries/#blockchainaccountid -[CAIP-10]: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md -[CAIP-2]: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md -[eip712]: https://github.com/uport-project/ethereum-eip712-signature-2021-spec +did:pkh method specification is moved to the following URL: +https://github.com/w3c-ccg/did-pkh/blob/main/did-pkh-method-draft.md diff --git a/did-pkh/src/lib.rs b/did-pkh/src/lib.rs index 33823fbae..ade6e3574 100644 --- a/did-pkh/src/lib.rs +++ b/did-pkh/src/lib.rs @@ -459,7 +459,7 @@ fn generate_caip10_eip155( key: &JWK, ref_opt: Option, ) -> Result { - let hash = ssi::keccak_hash::hash_public_key(key)?; + let hash = ssi::keccak_hash::hash_public_key_eip55(key)?; let reference = ref_opt.unwrap_or_else(|| REFERENCE_EIP155_ETHEREUM_MAINNET.to_string()); Ok(BlockchainAccountId { account_address: hash, diff --git a/did-tezos/src/lib.rs b/did-tezos/src/lib.rs index 3f5533ffa..b4702ce5d 100644 --- a/did-tezos/src/lib.rs +++ b/did-tezos/src/lib.rs @@ -23,6 +23,8 @@ use serde_json::Value; use std::collections::BTreeMap; use std::convert::TryInto; use std::default::Default; +use std::str::FromStr; +use std::string::ToString; /// did:tz DID Method /// @@ -37,6 +39,40 @@ impl Default for DIDTz { } } +#[derive(Clone, Debug)] +enum Prefix { + TZ1, + TZ2, + TZ3, + KT1, +} + +impl FromStr for Prefix { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "tz1" => Prefix::TZ1, + "tz2" => Prefix::TZ2, + "tz3" => Prefix::TZ3, + "KT1" => Prefix::KT1, + _ => return Err(()), + }) + } +} + +impl ToString for Prefix { + fn to_string(&self) -> String { + match self { + Prefix::TZ1 => "tz1", + Prefix::TZ2 => "tz2", + Prefix::TZ3 => "tz3", + Prefix::KT1 => "KT1", + } + .to_string() + } +} + #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl DIDResolver for DIDTz { @@ -90,18 +126,17 @@ impl DIDResolver for DIDTz { } }; - let prefix = match address.get(0..3) { - Some(prefix) => prefix, - None => { - return ( - ResolutionMetadata::from_error(ERROR_INVALID_DID), - None, - None, - ) - } - }; - let (_curve, proof_type, proof_type_iri) = match prefix_to_curve_type(prefix) { - Some(addr) => addr, + let prefix: Prefix = match address.get(0..3) { + Some(prefix) => match Prefix::from_str(prefix) { + Ok(p) => p, + Err(_) => { + return ( + ResolutionMetadata::from_error(ERROR_INVALID_DID), + None, + None, + ) + } + }, None => { return ( ResolutionMetadata::from_error(ERROR_INVALID_DID), @@ -110,6 +145,7 @@ impl DIDResolver for DIDTz { ) } }; + let (_curve, proof_type, proof_type_iri) = prefix_to_curve_type(prefix.clone()); let vm_didurl = DIDURL { did: did.to_string(), @@ -171,7 +207,7 @@ impl DIDResolver for DIDTz { }; if let (Some(service), Some(vm)) = - match DIDTz::tier2_resolution(tzkt_url, did, &address).await { + match DIDTz::tier2_resolution(prefix.clone(), tzkt_url, did, &address).await { Ok(res) => res, Err(e) => { return ( @@ -266,26 +302,24 @@ impl DIDResolver for DIDTz { } // addr must be at least 4 bytes -fn prefix_to_curve_type(prefix: &str) -> Option<(&'static str, &'static str, &'static str)> { - let curve_type = match prefix { - "tz1" => ( +fn prefix_to_curve_type(prefix: Prefix) -> (&'static str, &'static str, &'static str) { + match prefix { + Prefix::TZ1 | Prefix::KT1 => ( "Ed25519", "Ed25519PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021", "https://w3id.org/security#Ed25519PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021", ), - "tz2" => ( + Prefix::TZ2 => ( "secp256k1", "EcdsaSecp256k1RecoveryMethod2020", "https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoveryMethod2020", ), - "tz3" => ( + Prefix::TZ3 => ( "P-256", "P256PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021", "https://w3id.org/security#P256PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021", ), - _ => return None, - }; - Some(curve_type) + } } fn get_public_key_from_doc(doc: &Document, auth_vm_id: &str) -> Option { @@ -410,11 +444,15 @@ impl DIDTz { } async fn tier2_resolution( + prefix: Prefix, tzkt_url: &str, did: &str, address: &str, ) -> Result<(Option, Option)> { - if let Some(did_manager) = explorer::retrieve_did_manager(tzkt_url, address).await? { + if let Some(did_manager) = match prefix { + Prefix::KT1 => Some(address.to_string()), + _ => explorer::retrieve_did_manager(tzkt_url, address).await?, + } { Ok(( Some(explorer::execute_service_view(tzkt_url, did, &did_manager).await?), Some(explorer::execute_auth_view(tzkt_url, &did_manager).await?), @@ -426,7 +464,7 @@ impl DIDTz { async fn tier3_updates( &self, - prefix: &str, + prefix: Prefix, doc: &mut Document, updates: Updates, ) -> Result<()> { @@ -435,10 +473,7 @@ impl DIDTz { for jws in patches { let mut doc_json = serde_json::to_value(&mut *doc)?; let (patch_metadata, _) = decode_unverified(&jws)?; - let curve = prefix_to_curve_type(prefix) - .ok_or_else(|| anyhow!("Unsupported curve."))? - .0 - .to_string(); + let curve = prefix_to_curve_type(prefix.clone()).0.to_string(); let kid = match patch_metadata.key_id { Some(k) => k, None => return Err(anyhow!("No kid in JWS JSON patch.")), @@ -464,7 +499,7 @@ impl DIDTz { }; if let Some(public_key) = get_public_key_from_doc(&kid_doc, &kid) { let jwk = match prefix { - "tz1" => { + Prefix::TZ1 | Prefix::KT1 => { let pk = bs58::decode(public_key) .with_check(None) .into_vec() @@ -488,7 +523,7 @@ impl DIDTz { } } #[cfg(feature = "secp256k1")] - "tz2" => { + Prefix::TZ2 => { let pk = bs58::decode(public_key) .with_check(None) .into_vec() @@ -500,7 +535,7 @@ impl DIDTz { })? } #[cfg(feature = "secp256r1")] - "tz3" => { + Prefix::TZ3 => { let pk = bs58::decode(public_key) .with_check(None) .into_vec() @@ -511,7 +546,8 @@ impl DIDTz { anyhow!("Couldn't create JWK from P-256 public key: {}", e) })? } - p => return Err(anyhow!("{} not supported yet.", p)), + #[allow(unreachable_patterns)] + p => return Err(anyhow!("{} support not enabled.", p.to_string())), }; let (_, patch_) = decode_verify(&jws, &jwk)?; patch( @@ -548,6 +584,7 @@ mod tests { const TZ1_JSON: &'static str = "{\"kty\":\"OKP\",\"crv\":\"Ed25519\",\"x\":\"GvidwVqGgicuL68BRM89OOtDzK1gjs8IqUXFkjKkm8Iwg18slw==\",\"d\":\"K44dAtJ-MMl-JKuOupfcGRPI5n3ZVH_Gk65c6Rcgn_IV28987PMw_b6paCafNOBOi5u-FZMgGJd3mc5MkfxfwjCrXQM-\"}"; const LIVE_TZ1: &str = "tz1giDGsifWB9q9siekCKQaJKrmC9da5M43J"; + const LIVE_KT1: &str = "KT1ACXxefCq3zVG9cth4whZqS1XYK9Qsn8Gi"; const LIVE_NETWORK: &str = "NetXdQprcVkpaWU"; const JSON_PATCH: &str = r#"{"ietf-json-patch": [ { @@ -1134,7 +1171,7 @@ mod tests { let jws = encode_sign(ssi::jwk::Algorithm::EdDSA, JSON_PATCH, &key).unwrap(); let json_update = Updates::SignedIetfJsonPatch(vec![jws.clone()]); DIDTZ - .tier3_updates("tz1", &mut doc, json_update) + .tier3_updates(Prefix::TZ1, &mut doc, json_update) .await .unwrap(); assert_eq!( @@ -1196,7 +1233,7 @@ mod tests { let jws = encode_sign(ssi::jwk::Algorithm::ES256KR, JSON_PATCH, &key).unwrap(); let json_update = Updates::SignedIetfJsonPatch(vec![jws.clone()]); DIDTZ - .tier3_updates("tz2", &mut doc, json_update) + .tier3_updates(Prefix::TZ2, &mut doc, json_update) .await .unwrap(); assert_eq!( @@ -1257,7 +1294,7 @@ mod tests { let jws = encode_sign(ssi::jwk::Algorithm::ES256, JSON_PATCH, &key).unwrap(); let json_update = Updates::SignedIetfJsonPatch(vec![jws.clone()]); DIDTZ - .tier3_updates("tz3", &mut doc, json_update) + .tier3_updates(Prefix::TZ3, &mut doc, json_update) .await .unwrap(); assert_eq!( @@ -1359,6 +1396,49 @@ mod tests { // assert_eq!(d, expected); } + #[tokio::test] + async fn test_full_resolution_kt1() { + let live_did_manager = format!("did:tz:{}", LIVE_KT1); + + let (res_meta, res_doc, _res_doc_meta) = DIDTZ + .resolve(&live_did_manager, &ResolutionInputMetadata::default()) + .await; + assert_eq!(res_meta.error, None); + let d = res_doc.unwrap(); + let expected = Document { + id: live_did_manager.clone(), + verification_method: Some(vec![ + VerificationMethod::Map(VerificationMethodMap { + id: format!("{}#blockchainAccountId", live_did_manager), + type_: "Ed25519PublicKeyBLAKE2BDigestSize20Base58CheckEncoded2021".to_string(), + blockchain_account_id: Some(format!("tezos:{}:{}", LIVE_NETWORK, LIVE_KT1)), + controller: live_did_manager.clone(), + property_set: None, + ..Default::default() + }), + VerificationMethod::DIDURL(DIDURL { + did: format!("did:pkh:tz:{}", LIVE_TZ1), + path_abempty: "".to_string(), + query: None, + fragment: Some("TezosMethod2021".to_string()), + }), + ]), + service: Some(vec![Service { + id: format!("{}#discovery", live_did_manager), + type_: OneOrMany::One("TezosDiscoveryService".to_string()), + service_endpoint: Some(OneOrMany::One(ServiceEndpoint::URI( + "http://example.com".to_string(), + ))), + property_set: None, + }]), + ..Default::default() + }; + assert_eq!(d.id, expected.id); + assert_eq!(d.controller, expected.controller); + assert_eq!(d.verification_method, expected.verification_method); + assert_eq!(d.service, expected.service); + } + #[tokio::test] #[cfg(feature = "secp256r1")] async fn credential_prove_verify_did_tz3() { diff --git a/src/caip10.rs b/src/caip10.rs index 8e902e807..6df495766 100644 --- a/src/caip10.rs +++ b/src/caip10.rs @@ -49,8 +49,17 @@ impl BlockchainAccountId { ("tezos", _net) => blakesig::hash_public_key(jwk) .map_err(|e| BlockchainAccountIdVerifyError::HashError(e.to_string())), #[cfg(feature = "keccak-hash")] - ("eip155", _net) => crate::keccak_hash::hash_public_key(jwk) - .map_err(|e| BlockchainAccountIdVerifyError::HashError(e.to_string())), + // If account address contains uppercase, check EIP-55 checksum. + // Otherwise, assume EIP-55 is not being used. + ("eip155", _net) => if self + .account_address + .contains(|c: char| c.is_ascii_uppercase()) + { + crate::keccak_hash::hash_public_key_eip55(jwk) + } else { + crate::keccak_hash::hash_public_key(jwk) + } + .map_err(|e| BlockchainAccountIdVerifyError::HashError(e.to_string())), ("solana", _net) => encode_ed25519(jwk) .map_err(|e| BlockchainAccountIdVerifyError::HashError(e.to_string())), // Bitcoin diff --git a/src/error.rs b/src/error.rs index e767bdbe2..79584b7ff 100644 --- a/src/error.rs +++ b/src/error.rs @@ -201,6 +201,7 @@ pub enum Error { FromHex(hex::FromHexError), Base58(bs58::decode::Error), HexString, + ExpectedLowercase, SignaturePrefix, KeyPrefix, UnableToResolve(String), @@ -352,6 +353,7 @@ impl fmt::Display for Error { Error::UnknownProcessingMode(mode) => write!(f, "Unknown processing mode '{}'", mode), Error::UnknownRdfDirection(direction) => write!(f, "Unknown RDF direction '{}'", direction), Error::HexString => write!(f, "Expected string beginning with '0x'"), + Error::ExpectedLowercase => write!(f, "Expected string to contain only lowercase"), Error::SignaturePrefix => write!(f, "Unknown signature prefix"), Error::KeyPrefix => write!(f, "Unknown key prefix"), Error::UnableToResolve(error) => write!(f, "Unable to resolve: {}", error), diff --git a/src/hash.rs b/src/hash.rs index 2b4b97dcb..100ba741a 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,20 +1,22 @@ use crate::error::Error; -#[cfg(feature = "sha2")] +#[cfg(any(feature = "sha2", feature = "ring"))] pub fn sha256(data: &[u8]) -> Result<[u8; 32], Error> { - use sha2::Digest; - let mut hasher = sha2::Sha256::new(); - hasher.update(data); - let hash = hasher.finalize().into(); - Ok(hash) -} - -#[cfg(feature = "ring")] -pub fn sha256(data: &[u8]) -> Result<[u8; 32], Error> { - use ring::digest; - use std::convert::TryInto; - let hash = digest::digest(&digest::SHA256, data).as_ref().try_into()?; - Ok(hash) + #[cfg(feature = "sha2")] + { + use sha2::Digest; + let mut hasher = sha2::Sha256::new(); + hasher.update(data); + let hash = hasher.finalize().into(); + Ok(hash) + } + #[cfg(feature = "ring")] + { + use ring::digest; + use std::convert::TryInto; + let hash = digest::digest(&digest::SHA256, data).as_ref().try_into()?; + Ok(hash) + } } #[cfg(test)] diff --git a/src/jwk.rs b/src/jwk.rs index 9e0ddc050..609f3e8b1 100644 --- a/src/jwk.rs +++ b/src/jwk.rs @@ -230,6 +230,9 @@ pub enum Algorithm { /// https://github.com/decentralized-identity/EcdsaSecp256k1RecoverySignature2020#es256k-r #[serde(rename = "ES256K-R")] ES256KR, + /// like ES256K-R but using Keccak-256 instead of SHA-256 + #[serde(rename = "ES256K-R")] + ESKeccakKR, ESBlake2b, ESBlake2bK, None, diff --git a/src/jws.rs b/src/jws.rs index 394637f13..feb83a8f4 100644 --- a/src/jws.rs +++ b/src/jws.rs @@ -6,6 +6,8 @@ use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::convert::TryFrom; +pub type VerificationWarnings = Vec; + // RFC 7515 - JSON Web Signature (JWS) // RFC 7797 - JSON Web Signature (JWS) Unencoded Payload Option @@ -176,6 +178,18 @@ pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result { + use k256::ecdsa::signature::{Signature, Signer}; + let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; + if curve != "secp256k1" { + return Err(Error::CurveNotImplemented(curve.to_string())); + } + let secret_key = k256::SecretKey::try_from(ec)?; + let signing_key = k256::ecdsa::SigningKey::from(secret_key); + let sig: k256::ecdsa::recoverable::Signature = signing_key.try_sign(data)?; + sig.as_bytes().to_vec() + } #[cfg(feature = "p256")] Algorithm::ESBlake2b => { // We will be able to use the blake2 crate directly once it allow 32B output @@ -230,12 +244,13 @@ pub fn sign_bytes_b64(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result Result<(), Error> { +) -> Result { + let mut warnings = VerificationWarnings::default(); if let Some(key_algorithm) = key.algorithm { if key_algorithm != algorithm && !(key_algorithm == Algorithm::EdDSA && algorithm == Algorithm::EdBlake2b) @@ -358,7 +373,28 @@ pub fn verify_bytes( .map_err(|e| Error::Secp256k1Parse("Error parsing signature".to_string()))??; let hash = crate::hash::sha256(data)?; let digest = Digest::chain(::new(), &hash); - verifying_key.verify_digest(digest, &sig)?; + if let Err(_e) = verifying_key.verify_digest(digest, &sig) { + // Legacy mode: allow using Keccak-256 instead of SHA-256 + verify_bytes(Algorithm::ESKeccakKR, data, key, signature)?; + warnings + .push("Signature uses legacy mode ES256K-R with Keccak-256".to_string()); + } + } + #[cfg(feature = "k256")] + Algorithm::ESKeccakKR => { + use k256::ecdsa::signature::Verifier; + use std::panic; + let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; + if curve != "secp256k1" { + return Err(Error::CurveNotImplemented(curve.to_string())); + } + let public_key = k256::PublicKey::try_from(ec)?; + let verifying_key = k256::ecdsa::VerifyingKey::from(public_key); + let sig = panic::catch_unwind(|| { + k256::ecdsa::recoverable::Signature::try_from(signature) + }) + .map_err(|e| Error::Secp256k1Parse("Error parsing signature".to_string()))??; + verifying_key.verify(data, &sig)?; } #[cfg(feature = "p256")] Algorithm::ESBlake2b => { @@ -408,6 +444,16 @@ pub fn verify_bytes( }, _ => return Err(Error::KeyTypeNotImplemented), } + Ok(warnings) +} + +pub fn verify_bytes( + algorithm: Algorithm, + data: &[u8], + key: &JWK, + signature: &[u8], +) -> Result<(), Error> { + verify_bytes_warnable(algorithm, data, key, signature)?; Ok(()) } @@ -437,6 +483,16 @@ pub fn recover(algorithm: Algorithm, data: &[u8], signature: &[u8]) -> Result { + let sig = k256::ecdsa::recoverable::Signature::try_from(signature)?; + let recovered_key = sig.recover_verify_key(data)?; + use crate::jwk::ECParams; + let jwk = JWK::from(JWKParams::EC(ECParams::try_from( + &k256::PublicKey::from_sec1_bytes(&recovered_key.to_bytes())?, + )?)); + Ok(jwk) + } _ => { let _ = data; let _ = signature; @@ -595,6 +651,26 @@ pub fn detached_recover(jws: &str, payload_enc: &[u8]) -> Result<(Header, JWK), Ok((header, key)) } +pub(crate) fn detached_recover_legacy_keccak_es256kr( + jws: &str, + payload_enc: &[u8], +) -> Result<(Header, JWK), Error> { + let (header_b64, signature_b64) = crate::jws::split_detached_jws(jws)?; + let DecodedJWS { + mut header, + signing_input, + payload: _, + signature, + } = decode_jws_parts(header_b64, payload_enc, signature_b64)?; + // Allow ESKeccakK-R misimplementation of ES256K-R, for legacy reasons. + if header.algorithm != Algorithm::ES256KR { + return Err(Error::AlgorithmMismatch); + } + header.algorithm = Algorithm::ESKeccakKR; + let key = recover(header.algorithm, &signing_input, &signature)?; + Ok((header, key)) +} + pub fn decode_verify(jws: &str, key: &JWK) -> Result<(Header, Vec), Error> { let (header_b64, payload_enc, signature_b64) = split_jws(jws)?; let DecodedJWS { @@ -674,6 +750,22 @@ mod tests { verify_bytes(Algorithm::ES256KR, data, &recovered_key, &sig).unwrap(); let other_key = JWK::generate_secp256k1().unwrap(); verify_bytes(Algorithm::ES256KR, data, &other_key, &sig).unwrap_err(); + + // ESKeccakK-R + let key = JWK { + algorithm: Some(Algorithm::ESKeccakKR), + ..key + }; + verify_bytes(Algorithm::ESKeccakKR, data, &key, &sig).unwrap_err(); + verify_bytes(Algorithm::ESKeccakKR, bad_data, &key, &sig).unwrap_err(); + + // Test recovery (ESKeccakK-R) + let sig = sign_bytes(Algorithm::ESKeccakKR, data, &key).unwrap(); + verify_bytes(Algorithm::ESKeccakKR, data, &key, &sig).unwrap(); + verify_bytes(Algorithm::ESKeccakKR, bad_data, &key, &sig).unwrap_err(); + let recovered_key = recover(Algorithm::ESKeccakKR, data, &sig).unwrap(); + verify_bytes(Algorithm::ESKeccakKR, data, &recovered_key, &sig).unwrap(); + verify_bytes(Algorithm::ESKeccakKR, data, &other_key, &sig).unwrap_err(); } #[test] diff --git a/src/keccak_hash.rs b/src/keccak_hash.rs index f1d092bf7..e2b64ce31 100644 --- a/src/keccak_hash.rs +++ b/src/keccak_hash.rs @@ -20,6 +20,10 @@ pub fn bytes_to_lowerhex(bytes: &[u8]) -> String { .collect::() } +/// Compute a hash of a public key as an Ethereum address. +/// +/// The hash is of the public key (64 bytes), using Keccak. The hash is truncated to the last 20 +/// bytes, lowercase-hex-encoded, and prefixed with "0x" to form the resulting string. pub fn hash_public_key(jwk: &JWK) -> Result { let ec_params = match jwk.params { Params::EC(ref params) => params, @@ -34,6 +38,42 @@ pub fn hash_public_key(jwk: &JWK) -> Result { Ok(hash_last20_hex) } +/// Compute a hash of a public key as an Ethereum address, with EIP-55 checksum. +/// +/// Same as [`hash_public_key_lowercase`], but with [EIP-55] mixed-case checksum encoding (using [`eip55_checksum_addr`]). +/// [EIP-55]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md +pub fn hash_public_key_eip55(jwk: &JWK) -> Result { + let hash_lowercase = hash_public_key(jwk)?; + eip55_checksum_addr(&hash_lowercase) +} + +/// Convert an Ethereum address into a mixed-case Ethereum address using [EIP-55] checksum +/// encoding. +/// Input string must begin with "0x" and be in lowercase. +/// Output string begins with "0x". +/// [EIP-55]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md +pub fn eip55_checksum_addr(addr: &str) -> Result { + let addr = addr.strip_prefix("0x").ok_or(Error::HexString)?; + if addr.contains(|c: char| c.is_ascii_uppercase()) { + return Err(Error::ExpectedLowercase); + } + let eip55_hash = keccak(addr.as_bytes()).to_fixed_bytes(); + let checksummed_addr = addr + .chars() + .enumerate() + .map(|(i, c)| { + if matches!(c, 'a' | 'b' | 'c' | 'd' | 'e' | 'f') + && (eip55_hash[i >> 1] & if i % 2 == 0 { 128 } else { 8 } != 0) + { + c.to_ascii_uppercase() + } else { + c + } + }) + .collect::(); + Ok("0x".to_string() + &checksummed_addr) +} + pub fn prefix_personal_message(msg: &str) -> Vec { let msg_bytes = msg.as_bytes(); let prefix = format!("\x19Ethereum Signed Message:\n{}", msg_bytes.len()); @@ -75,4 +115,44 @@ mod tests { "0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede" ); } + + #[test] + fn test_eip55() { + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#test-cases + // All caps + assert_eq!( + eip55_checksum_addr("0x52908400098527886e0f7030069857d2e4169ee7").unwrap(), + "0x52908400098527886E0F7030069857D2E4169EE7" + ); + assert_eq!( + eip55_checksum_addr("0x8617e340b3d01fa5f11f306f4090fd50e238070d").unwrap(), + "0x8617E340B3D01FA5F11F306F4090FD50E238070D" + ); + // All Lower + assert_eq!( + eip55_checksum_addr("0xde709f2102306220921060314715629080e2fb77").unwrap(), + "0xde709f2102306220921060314715629080e2fb77" + ); + assert_eq!( + eip55_checksum_addr("0x27b1fdb04752bbc536007a920d24acb045561c26").unwrap(), + "0x27b1fdb04752bbc536007a920d24acb045561c26" + ); + // Normal + assert_eq!( + eip55_checksum_addr("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed").unwrap(), + "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed" + ); + assert_eq!( + eip55_checksum_addr("0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359").unwrap(), + "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359" + ); + assert_eq!( + eip55_checksum_addr("0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb").unwrap(), + "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB" + ); + assert_eq!( + eip55_checksum_addr("0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb").unwrap(), + "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb" + ); + } } diff --git a/src/ldp.rs b/src/ldp.rs index 0749d8a55..3c5047adb 100644 --- a/src/ldp.rs +++ b/src/ldp.rs @@ -237,7 +237,7 @@ pub trait ProofSuite { ) -> Result; } -pub type VerificationWarnings = Vec; +pub use crate::jws::VerificationWarnings; #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] @@ -631,8 +631,7 @@ async fn verify_nojws( let key = resolve_key(&verification_method, resolver).await?; let message = to_jws_payload(document, proof).await?; let (_base, sig) = multibase::decode(proof_value)?; - crate::jws::verify_bytes(algorithm, &message, &key, &sig)?; - Ok(Default::default()) + crate::jws::verify_bytes_warnable(algorithm, &message, &key, &sig) } pub struct RsaSignature2018; @@ -952,8 +951,17 @@ impl ProofSuite for EcdsaSecp256k1RecoverySignature2020 { } let message = to_jws_payload(document, proof).await?; let (_header, jwk) = crate::jws::detached_recover(jws, &message)?; - vm.match_jwk(&jwk)?; - Ok(Default::default()) + let mut warnings = VerificationWarnings::default(); + if let Err(_e) = vm.match_jwk(&jwk) { + // Legacy mode: allow using Keccak-256 instead of SHA-256 + let (_header, jwk) = crate::jws::detached_recover_legacy_keccak_es256kr(jws, &message)?; + vm.match_jwk(&jwk)?; + warnings.push( + "Signature uses legacy mode EcdsaSecp256k1RecoveryMethod2020 with Keccak-256" + .to_string(), + ); + } + Ok(warnings) } } @@ -1687,9 +1695,9 @@ impl ProofSuite for TezosSignature2021 { }; // VM must have either publicKeyJwk or blockchainAccountId. - if let Some(vm_jwk) = vm.public_key_jwk { - // If VM has publicKey, use that to veify the signature. - crate::jws::verify_bytes(algorithm, &micheline, &vm_jwk, &sig)?; + let warnings = if let Some(vm_jwk) = vm.public_key_jwk { + // If VM has publicKey, use that to verify the signature. + crate::jws::verify_bytes_warnable(algorithm, &micheline, &vm_jwk, &sig)? // Note: VM blockchainAccountId is ignored in this case. } else if let Some(account_id) = account_id_opt { // VM does not have publicKeyJwk: proof must have public key @@ -1697,14 +1705,14 @@ impl ProofSuite for TezosSignature2021 { // Proof has public key: verify it with blockchainAccountId, account_id.verify(&proof_jwk)?; // and verify the signature. - crate::jws::verify_bytes(algorithm, &micheline, &proof_jwk, &sig)?; + crate::jws::verify_bytes_warnable(algorithm, &micheline, &proof_jwk, &sig)? } else { return Err(Error::MissingKey); } } else { return Err(Error::MissingKey); }; - Ok(Default::default()) + Ok(warnings) } } @@ -1834,9 +1842,9 @@ impl ProofSuite for TezosJcsSignature2021 { }; // VM must have either publicKeyJwk or blockchainAccountId. - if let Some(vm_jwk) = vm.public_key_jwk { - // If VM has publicKey, use that to veify the signature. - crate::jws::verify_bytes(algorithm, &micheline, &vm_jwk, &sig)?; + let mut warnings = if let Some(vm_jwk) = vm.public_key_jwk { + // If VM has publicKey, use that to verify the signature. + crate::jws::verify_bytes_warnable(algorithm, &micheline, &vm_jwk, &sig)? // Note: VM blockchainAccountId is ignored in this case. } else if let Some(account_id) = account_id_opt { // VM does not have publicKeyJwk: proof must have public key @@ -1850,14 +1858,15 @@ impl ProofSuite for TezosJcsSignature2021 { // Proof has public key: verify it with blockchainAccountId, account_id.verify(&proof_jwk)?; // and verify the signature. - crate::jws::verify_bytes(algorithm, &micheline, &proof_jwk, &sig)?; + crate::jws::verify_bytes_warnable(algorithm, &micheline, &proof_jwk, &sig)? } else { return Err(Error::MissingKey); } } else { return Err(Error::MissingKey); }; - Ok(vec!["TezosJcsSignature2021 is experimental.".to_string()]) + warnings.push("TezosJcsSignature2021 is experimental.".to_string()); + Ok(warnings) } } @@ -1945,8 +1954,7 @@ impl ProofSuite for SolanaSignature2021 { let tx = crate::soltx::LocalSolanaTransaction::with_message(&message); let bytes = tx.to_bytes(); let sig = bs58::decode(&sig_b58).into_vec()?; - crate::jws::verify_bytes(Algorithm::EdDSA, &bytes, &key, &sig)?; - Ok(Default::default()) + crate::jws::verify_bytes_warnable(Algorithm::EdDSA, &bytes, &key, &sig) } } @@ -2093,8 +2101,7 @@ impl ProofSuite for JsonWebSignature2020 { self.validate_algorithm(header.algorithm)?; let key = resolve_key(verification_method, resolver).await?; self.validate_key_and_algorithm(&key, header.algorithm)?; - crate::jws::verify_bytes(header.algorithm, &signing_input, &key, &signature)?; - Ok(Default::default()) + crate::jws::verify_bytes_warnable(header.algorithm, &signing_input, &key, &signature) } async fn complete( &self, diff --git a/src/lib.rs b/src/lib.rs index 59aee73e3..5cb1c8dea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + pub mod bbs; pub mod blakesig; pub mod caip10; diff --git a/src/revocation.rs b/src/revocation.rs index 773d6a16c..de52cab4c 100644 --- a/src/revocation.rs +++ b/src/revocation.rs @@ -18,6 +18,9 @@ type URL = String; /// pub const MIN_BITSTRING_LENGTH: usize = 131072; +/// Maximum size of a revocation list credential loaded using [`load_credential`]. +pub const MAX_RESPONSE_LENGTH: usize = 2097152; // 2MB + const EMPTY_RLIST: &str = "H4sIAAAAAAAA_-3AMQEAAADCoPVPbQwfKAAAAAAAAAAAAAAAAAAAAOBthtJUqwBAAAA"; /// Credential Status object for use in a Verifiable Credential. @@ -359,6 +362,19 @@ pub enum LoadResourceError { NotFound, #[error("HTTP error: {0}")] HTTP(String), + /// The resource is larger than an expected/allowed maximum size. + #[error("Resource is too large: {size}, expected maximum: {max}")] + TooLarge { + /// The size of the resource so far, in bytes. + size: usize, + /// Maximum expected size of the resource, in bytes. + /// + /// e.g. [`MAX_RESPONSE_LENGTH`] + max: usize, + }, + /// Unable to convert content-length header value. + #[error("Unable to convert content-length header value")] + ContentLengthConversion(#[source] std::num::TryFromIntError), } async fn load_resource(url: &str) -> Result, LoadResourceError> { @@ -391,12 +407,66 @@ async fn load_resource(url: &str) -> Result, LoadResourceError> { } return Err(LoadResourceError::HTTP(err.to_string())); } - let bytes = resp - .bytes() - .await - .map_err(|e| LoadResourceError::Response(e.to_string()))? - .to_vec(); - Ok(bytes) + #[allow(unused_variables)] + let content_length_opt = if let Some(content_length) = resp.content_length() { + let len = + usize::try_from(content_length).map_err(LoadResourceError::ContentLengthConversion)?; + if len > MAX_RESPONSE_LENGTH { + // Fail early if content-length header indicates body is too large. + return Err(LoadResourceError::TooLarge { + size: len, + max: MAX_RESPONSE_LENGTH, + }); + } + Some(len) + } else { + None + }; + #[cfg(target_arch = "wasm32")] + { + // Reqwest's WASM backend doesn't offer streamed/chunked response reading. + // So we cannot check the response size while reading the response here. + // Relevant issue: https://github.com/seanmonstar/reqwest/issues/1234 + // Instead, we hope that the content-length is correct, read the body all at once, + // and apply the length check afterwards, for consistency. + let bytes = resp + .bytes() + .await + .map_err(|e| LoadResourceError::Response(e.to_string()))? + .to_vec(); + if bytes.len() > MAX_RESPONSE_LENGTH { + return Err(LoadResourceError::TooLarge { + size: bytes.len(), + max: MAX_RESPONSE_LENGTH, + }); + } + Ok(bytes) + } + #[cfg(not(target_arch = "wasm32"))] + { + // For non-WebAssembly, read the response up to the allowed maximimum size. + let mut bytes = if let Some(len) = content_length_opt { + Vec::with_capacity(len) + } else { + Vec::new() + }; + let mut resp = resp; + while let Some(chunk) = resp + .chunk() + .await + .map_err(|e| LoadResourceError::Response(e.to_string()))? + { + let len = bytes.len() + chunk.len(); + if len > MAX_RESPONSE_LENGTH { + return Err(LoadResourceError::TooLarge { + size: len, + max: MAX_RESPONSE_LENGTH, + }); + } + bytes.append(&mut chunk.to_vec()); + } + Ok(bytes) + } } #[derive(Error, Debug)] @@ -409,6 +479,8 @@ pub enum LoadCredentialError { /// Fetch a credential from a HTTP(S) URL. /// The resulting verifiable credential is not yet validated or verified. +/// +/// The size of the loaded credential must not be greater than [`MAX_RESPONSE_LENGTH`]. pub async fn load_credential(url: &str) -> Result { let data = load_resource(url).await?; // TODO: support JWT-VC diff --git a/src/vc.rs b/src/vc.rs index 6740ce5e2..65016c9f6 100644 --- a/src/vc.rs +++ b/src/vc.rs @@ -14,7 +14,7 @@ use crate::one_or_many::OneOrMany; use crate::rdf::DataSet; use async_trait::async_trait; -use chrono::{Duration, LocalResult, prelude::*}; +use chrono::{prelude::*, Duration, LocalResult}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -400,14 +400,16 @@ impl std::convert::TryFrom> for NumericDate { impl std::convert::Into> for NumericDate { fn into(self) -> DateTime { - let (whole_seconds, fractional_nanoseconds) = self.into_whole_seconds_and_fractional_nanoseconds(); + let (whole_seconds, fractional_nanoseconds) = + self.into_whole_seconds_and_fractional_nanoseconds(); Utc.timestamp(whole_seconds, fractional_nanoseconds) } } impl std::convert::Into>> for NumericDate { fn into(self) -> LocalResult> { - let (whole_seconds, fractional_nanoseconds) = self.into_whole_seconds_and_fractional_nanoseconds(); + let (whole_seconds, fractional_nanoseconds) = + self.into_whole_seconds_and_fractional_nanoseconds(); Utc.timestamp_opt(whole_seconds, fractional_nanoseconds) } } @@ -846,7 +848,11 @@ impl Credential { } if let Some(iss) = claims.issuer { if let StringOrURI::URI(issuer_uri) = iss { - vc.issuer = Some(Issuer::URI(issuer_uri)); + if let Some(Issuer::Object(ref mut issuer)) = vc.issuer { + issuer.id = issuer_uri; + } else { + vc.issuer = Some(Issuer::URI(issuer_uri)); + } } else { return Err(Error::InvalidIssuer); } @@ -908,7 +914,7 @@ impl Credential { expiration_time, issuer: match issuer { Some(Issuer::URI(uri)) => Some(StringOrURI::URI(uri)), - Some(_) => return Err(Error::InvalidIssuer), + Some(Issuer::Object(object_with_id)) => Some(StringOrURI::URI(object_with_id.id)), None => None, }, not_before, @@ -1118,8 +1124,16 @@ impl Credential { }; let mut results = VerificationResult::new(); if matched_jwt { - match crate::jws::verify_bytes(header.algorithm, &signing_input, &key, &signature) { - Ok(()) => results.checks.push(Check::JWS), + match crate::jws::verify_bytes_warnable( + header.algorithm, + &signing_input, + &key, + &signature, + ) { + Ok(mut warnings) => { + results.checks.push(Check::JWS); + results.warnings.append(&mut warnings); + } Err(err) => results .errors .push(format!("Unable to filter proofs: {}", err)), @@ -1631,8 +1645,16 @@ impl Presentation { }; let mut results = VerificationResult::new(); if matched_jwt { - match crate::jws::verify_bytes(header.algorithm, &signing_input, &key, &signature) { - Ok(()) => results.checks.push(Check::JWS), + match crate::jws::verify_bytes_warnable( + header.algorithm, + &signing_input, + &key, + &signature, + ) { + Ok(mut warnings) => { + results.checks.push(Check::JWS); + results.warnings.append(&mut warnings); + } Err(err) => results .errors .push(format!("Unable to filter proofs: {}", err)), @@ -2273,22 +2295,58 @@ pub(crate) mod tests { #[test] fn numeric_date() { - assert_eq!(NumericDate::try_from_seconds(NumericDate::MIN.as_seconds()).unwrap(), NumericDate::MIN, "NumericDate::MIN value did not survive round trip"); - assert_eq!(NumericDate::try_from_seconds(NumericDate::MAX.as_seconds()).unwrap(), NumericDate::MAX, "NumericDate::MAX value did not survive round trip"); - - assert!(NumericDate::try_from_seconds(NumericDate::MIN.as_seconds() - 1.0e-6).is_err(), "NumericDate::MIN-1.0e-6 value did not hit out-of-range error"); - assert!(NumericDate::try_from_seconds(NumericDate::MAX.as_seconds() + 1.0e-6).is_err(), "NumericDate::MAX+1.0e-6 value did not hit out-of-range error"); - - assert!(NumericDate::try_from_seconds(NumericDate::MIN.as_seconds() + 1.0e-6).is_ok(), "NumericDate::MIN-1.0e-6 value did not hit out-of-range error"); - assert!(NumericDate::try_from_seconds(NumericDate::MAX.as_seconds() - 1.0e-6).is_ok(), "NumericDate::MAX+1.0e-6 value did not hit out-of-range error"); + assert_eq!( + NumericDate::try_from_seconds(NumericDate::MIN.as_seconds()).unwrap(), + NumericDate::MIN, + "NumericDate::MIN value did not survive round trip" + ); + assert_eq!( + NumericDate::try_from_seconds(NumericDate::MAX.as_seconds()).unwrap(), + NumericDate::MAX, + "NumericDate::MAX value did not survive round trip" + ); + + assert!( + NumericDate::try_from_seconds(NumericDate::MIN.as_seconds() - 1.0e-6).is_err(), + "NumericDate::MIN-1.0e-6 value did not hit out-of-range error" + ); + assert!( + NumericDate::try_from_seconds(NumericDate::MAX.as_seconds() + 1.0e-6).is_err(), + "NumericDate::MAX+1.0e-6 value did not hit out-of-range error" + ); + + assert!( + NumericDate::try_from_seconds(NumericDate::MIN.as_seconds() + 1.0e-6).is_ok(), + "NumericDate::MIN-1.0e-6 value did not hit out-of-range error" + ); + assert!( + NumericDate::try_from_seconds(NumericDate::MAX.as_seconds() - 1.0e-6).is_ok(), + "NumericDate::MAX+1.0e-6 value did not hit out-of-range error" + ); let one_microsecond = Duration::microseconds(1); - assert_eq!((NumericDate::MIN + one_microsecond) - one_microsecond, NumericDate::MIN, "NumericDate::MIN+1.0e-6 wasn't correctly represented"); - assert_eq!((NumericDate::MAX - one_microsecond) + one_microsecond, NumericDate::MAX, "NumericDate::MAX-1.0e-6 wasn't correctly represented"); + assert_eq!( + (NumericDate::MIN + one_microsecond) - one_microsecond, + NumericDate::MIN, + "NumericDate::MIN+1.0e-6 wasn't correctly represented" + ); + assert_eq!( + (NumericDate::MAX - one_microsecond) + one_microsecond, + NumericDate::MAX, + "NumericDate::MAX-1.0e-6 wasn't correctly represented" + ); // At the MIN and MAX, increasing by half a microsecond shouldn't alter MIN or MAX. - assert_eq!(NumericDate::MIN - Duration::nanoseconds(500), NumericDate::MIN, "NumericDate::MIN isn't the true min"); - assert_eq!(NumericDate::MAX + Duration::nanoseconds(500), NumericDate::MAX, "NumericDate::MAX isn't the true max"); + assert_eq!( + NumericDate::MIN - Duration::nanoseconds(500), + NumericDate::MIN, + "NumericDate::MIN isn't the true min" + ); + assert_eq!( + NumericDate::MAX + Duration::nanoseconds(500), + NumericDate::MAX, + "NumericDate::MAX isn't the true max" + ); } #[test]