Skip to content

Commit 45ef285

Browse files
committed
Merge branch 'main' into feat/identity-rebased-alpha
2 parents ffe2295 + f5c4fe9 commit 45ef285

File tree

76 files changed

+4338
-133
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+4338
-133
lines changed

.github/workflows/rust-deploy-docs.yml

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
name: Rust deploy crate docs
22

33
on:
4-
release:
5-
types: [published]
6-
74
workflow_dispatch:
85
inputs:
96
branch:
@@ -36,6 +33,10 @@ jobs:
3633
path: ./target/doc
3734
deploy:
3835
if: ${{ !inputs.dry-run }}
36+
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
37+
permissions:
38+
pages: write # to deploy to Pages
39+
id-token: write # to verify the deployment originates from an appropriate source
3940
environment:
4041
name: github-pages
4142
url: ${{ steps.deployment.outputs.page_url }}

.github/workflows/shared-release.yml

+3
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ jobs:
155155
if: ${{env.IS_RELEASE && inputs.create-github-release}}
156156
uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5
157157
with:
158+
# Token expires Jan 16, 2026
159+
# This is needed because of https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow#triggering-a-workflow-from-a-workflow
160+
token: ${{ secrets.GH_RELEASE_PUBLISH_PAT }}
158161
body_path: RELEASE_CHANGELOG.md
159162
prerelease: ${{env.IS_PRE_RELEASE}}
160163
tag_name: ${{env.CURRENT_VERSION}}

.github/workflows/upload-docs.yml

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ on:
99
description: 'Version to publish docs under (e.g. `v1.2.3-dev.1`)'
1010
required: true
1111

12+
env:
13+
GH_TOKEN: ${{ github.token }}
14+
1215
permissions:
1316
actions: 'write'
1417

CHANGELOG.md

+17-4
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,35 @@ This release is targeting IOTA Rebased networks and is meant for early testing.
88

99
Identities created on IOTA Stardust networks can be migrated via the [Stardust package](https://docs.iota.org/developer/stardust/stardust-migration)
1010

11+
## [v1.5.0](https://github.com/iotaledger/identity.rs/tree/v1.5.0) (2025-01-20)
12+
13+
[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v1.4.0...v1.5.0)
14+
15+
### Added
16+
17+
- SD-JWT VC implementation [\#1413](https://github.com/iotaledger/identity.rs/pull/1413)
18+
19+
### Patch
20+
21+
- Support %-encoded characters in DID URL [\#1496](https://github.com/iotaledger/identity.rs/pull/1496)
22+
- fix: serialization of status list [\#1423](https://github.com/iotaledger/identity.rs/pull/1423)
23+
1124
## [v1.4.0](https://github.com/iotaledger/identity.rs/tree/v1.4.0) (2024-09-23)
1225

1326
[Full Changelog](https://github.com/iotaledger/identity.rs/compare/v1.3.1...v1.4.0)
1427

1528
### Added
1629

17-
- Add feature to support custom `now_utc` implementations [\#1397](https://github.com/iotaledger/identity.rs/pull/1397)
30+
- Add support for custom JWS algorithms [\#1410](https://github.com/iotaledger/identity.rs/pull/1410)
1831
- Add support for `did:jwk` resolution [\#1404](https://github.com/iotaledger/identity.rs/pull/1404)
1932
- Linked Verifiable Presentations [\#1398](https://github.com/iotaledger/identity.rs/pull/1398)
20-
- Add support for custom JWS algorithms [\#1410](https://github.com/iotaledger/identity.rs/pull/1410)
33+
- Add feature to support custom `now_utc` implementations [\#1397](https://github.com/iotaledger/identity.rs/pull/1397)
2134

2235
### Patch
2336

24-
- Make `bls12_381_plus` dependency more flexible again [\#1393](https://github.com/iotaledger/identity.rs/pull/1393)
25-
- Mark `js-sys` as optional for identity_core [\#1405](https://github.com/iotaledger/identity.rs/pull/1405)
2637
- Remove dependency on `identity_core` default features [\#1408](https://github.com/iotaledger/identity.rs/pull/1408)
38+
- Mark `js-sys` as optional for identity\_core [\#1405](https://github.com/iotaledger/identity.rs/pull/1405)
39+
- Make `bls12_381_plus` dependency more flexible again [\#1393](https://github.com/iotaledger/identity.rs/pull/1393)
2740

2841
## [v1.3.1](https://github.com/iotaledger/identity.rs/tree/v1.3.1) (2024-06-12)
2942

bindings/wasm/identity_wasm/CHANGELOG.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## [wasm-v1.5.0](https://github.com/iotaledger/identity.rs/tree/wasm-v1.5.0) (2025-01-20)
4+
5+
[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v1.4.0...wasm-v1.5.0)
6+
7+
### Added
8+
9+
- SD-JWT VC implementation [\#1413](https://github.com/iotaledger/identity.rs/pull/1413)
10+
11+
### Patch
12+
13+
- Support %-encoded characters in DID URL [\#1496](https://github.com/iotaledger/identity.rs/pull/1496)
14+
- fix: serialization of status list [\#1423](https://github.com/iotaledger/identity.rs/pull/1423)
15+
316
## [wasm-v1.4.0](https://github.com/iotaledger/identity.rs/tree/wasm-v1.4.0) (2024-09-23)
417

518
[Full Changelog](https://github.com/iotaledger/identity.rs/compare/wasm-v1.3.1...wasm-v1.4.0)
@@ -8,7 +21,6 @@
821

922
- Add support for `did:jwk` resolution [\#1404](https://github.com/iotaledger/identity.rs/pull/1404)
1023
- Linked Verifiable Presentations [\#1398](https://github.com/iotaledger/identity.rs/pull/1398)
11-
- Add WASM bindings for EcDSA JWS Verifier [\#1396](https://github.com/iotaledger/identity.rs/pull/1396)
1224

1325
## [wasm-v1.3.1](https://github.com/iotaledger/identity.rs/tree/wasm-v1.3.1) (2024-06-28)
1426

bindings/wasm/identity_wasm/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "identity_wasm"
3-
version = "1.4.0"
3+
version = "1.5.0"
44
authors = ["IOTA Stiftung"]
55
edition = "2021"
66
homepage = "https://www.iota.org"
@@ -47,6 +47,7 @@ features = [
4747
"resolver",
4848
"domain-linkage",
4949
"sd-jwt",
50+
"sd-jwt-vc",
5051
"status-list-2021",
5152
"jpt-bbs-plus",
5253
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// Copyright 2020-2024 IOTA Stiftung
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import {
5+
IJwk,
6+
IJwkParams,
7+
IResolver,
8+
IssuerMetadata,
9+
Jwk,
10+
JwkType,
11+
JwsVerificationOptions,
12+
KeyBindingJwtBuilder,
13+
KeyBindingJWTValidationOptions,
14+
SdJwtVcBuilder,
15+
Sha256Hasher,
16+
Timestamp,
17+
TypeMetadataHelper,
18+
} from "@iota/identity-wasm/node";
19+
import { exportJWK, generateKeyPair, JWK, JWTHeaderParameters, JWTPayload, SignJWT } from "jose";
20+
21+
const vc_metadata: TypeMetadataHelper = JSON.parse(`{
22+
"vct": "https://example.com/education_credential",
23+
"name": "Betelgeuse Education Credential - Preliminary Version",
24+
"description": "This is our development version of the education credential. Don't panic.",
25+
"claims": [
26+
{
27+
"path": ["name"],
28+
"display": [
29+
{
30+
"lang": "de-DE",
31+
"label": "Vor- und Nachname",
32+
"description": "Der Name des Studenten"
33+
},
34+
{
35+
"lang": "en-US",
36+
"label": "Name",
37+
"description": "The name of the student"
38+
}
39+
],
40+
"sd": "allowed"
41+
},
42+
{
43+
"path": ["address"],
44+
"display": [
45+
{
46+
"lang": "de-DE",
47+
"label": "Adresse",
48+
"description": "Adresse zum Zeitpunkt des Abschlusses"
49+
},
50+
{
51+
"lang": "en-US",
52+
"label": "Address",
53+
"description": "Address at the time of graduation"
54+
}
55+
],
56+
"sd": "always"
57+
},
58+
{
59+
"path": ["address", "street_address"],
60+
"display": [
61+
{
62+
"lang": "de-DE",
63+
"label": "Straße"
64+
},
65+
{
66+
"lang": "en-US",
67+
"label": "Street Address"
68+
}
69+
],
70+
"sd": "always",
71+
"svg_id": "address_street_address"
72+
},
73+
{
74+
"path": ["degrees", null],
75+
"display": [
76+
{
77+
"lang": "de-DE",
78+
"label": "Abschluss",
79+
"description": "Der Abschluss des Studenten"
80+
},
81+
{
82+
"lang": "en-US",
83+
"label": "Degree",
84+
"description": "Degree earned by the student"
85+
}
86+
],
87+
"sd": "allowed"
88+
}
89+
]
90+
}`);
91+
92+
const keypair_jwk = async (): Promise<[JWK, JWK]> => {
93+
const [sk, pk] = await generateKeyPair("ES256").then(res => [res.privateKey, res.publicKey]);
94+
const sk_jwk = await exportJWK(sk);
95+
const pk_jwk = await exportJWK(pk);
96+
97+
return [sk_jwk, pk_jwk];
98+
};
99+
100+
const signer = async (header: object, payload: object, sk_jwk: JWK) => {
101+
return new SignJWT(payload as JWTPayload)
102+
.setProtectedHeader(header as JWTHeaderParameters)
103+
.sign(sk_jwk)
104+
.then(jws => new TextEncoder().encode(jws));
105+
};
106+
107+
export async function sdJwtVc() {
108+
const hasher = new Sha256Hasher();
109+
const issuer = "https://example.com/";
110+
const [sk_jwk, pk_jwk] = await keypair_jwk();
111+
const issuer_public_jwk = { ...pk_jwk, kty: JwkType.Ec, kid: "key1" } as IJwk;
112+
const issuer_signer = (header: object, payload: object) => signer(header, payload, sk_jwk);
113+
const issuer_metadata = new IssuerMetadata(issuer, { jwks: { keys: [issuer_public_jwk] } });
114+
const dummy_resolver = {
115+
resolve: async (input: string) => {
116+
if (input == "https://example.com/.well-known/jwt-vc-issuer/") {
117+
return new TextEncoder().encode(JSON.stringify(issuer_metadata.toJSON()));
118+
}
119+
if (input == "https://example.com/.well-known/vct/education_credential") {
120+
return new TextEncoder().encode(JSON.stringify(vc_metadata));
121+
}
122+
},
123+
} as IResolver<string, Uint8Array>;
124+
const [holder_sk, holder_pk] = await keypair_jwk();
125+
const holder_public_jwk = { ...holder_pk, kty: JwkType.Ec, kid: "key2" } as IJwk;
126+
const holder_signer = (header: object, payload: object) => signer(header, payload, holder_sk);
127+
128+
/// Issuer creates an SD-JWT VC.
129+
let sd_jwt_vc = await new SdJwtVcBuilder({
130+
name: "John Doe",
131+
address: {
132+
street_address: "A random street",
133+
number: "3a",
134+
},
135+
degree: [],
136+
}, hasher)
137+
.header({ kid: "key1" })
138+
.vct("https://example.com/education_credential")
139+
.iat(Timestamp.nowUTC())
140+
.iss(issuer)
141+
.requireKeyBinding({ kid: holder_public_jwk.kid })
142+
.makeConcealable("/address/street_address")
143+
.makeConcealable("/address")
144+
.finish({ sign: issuer_signer }, "ES256");
145+
146+
console.log(`issued SD-JWT VC: ${sd_jwt_vc.toString()}`);
147+
148+
// Holder receives its SD-JWT VC and attaches its keybinding JWT.
149+
const kb_jwt = await new KeyBindingJwtBuilder()
150+
.iat(Timestamp.nowUTC())
151+
.header({ kid: holder_public_jwk.kid })
152+
.nonce("abcdefghi")
153+
.aud("https://example.com/verify")
154+
.finish(sd_jwt_vc.asSdJwt(), "ES256", { sign: holder_signer });
155+
const { disclosures, sdJwtVc } = sd_jwt_vc.intoPresentation(hasher).attachKeyBindingJwt(kb_jwt).finish();
156+
console.log(`presented SD-JWT VC: ${sdJwtVc}`);
157+
158+
// Verifier checks the presented sdJwtVc.
159+
await sdJwtVc.validate(dummy_resolver, hasher);
160+
sdJwtVc.validateKeyBinding(
161+
new Jwk(holder_public_jwk as IJwkParams),
162+
hasher,
163+
new KeyBindingJWTValidationOptions({ nonce: "abcdefghi", jwsOptions: new JwsVerificationOptions() }),
164+
);
165+
166+
console.log("The presented SdJwtVc is valid!");
167+
}

bindings/wasm/identity_wasm/examples/src/main.ts

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { deactivateIdentity } from "./0_basic/3_deactivate_did";
88
import { createVC } from "./0_basic/5_create_vc";
99
import { createVP } from "./0_basic/6_create_vp";
1010
import { revokeVC } from "./0_basic/7_revoke_vc";
11+
import { sdJwtVc } from "./1_advanced/10_sd_jwt_vc";
1112
import { customResolution } from "./1_advanced/4_custom_resolution";
1213
import { domainLinkage } from "./1_advanced/5_domain_linkage";
1314
import { sdJwt } from "./1_advanced/6_sd_jwt";
@@ -49,6 +50,8 @@ async function main() {
4950
return await zkp();
5051
case "9_zkp_revocation":
5152
return await zkp_revocation();
53+
case "10_sd_jwt_vc":
54+
return await sdJwtVc();
5255
default:
5356
throw "Unknown example name: '" + argument + "'";
5457
}

bindings/wasm/identity_wasm/package-lock.json

+37-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)