Skip to content

Commit 86c37e5

Browse files
authored
identity service: refactoring, documentation, and testing... #1289 (#1290)
Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
1 parent d589b82 commit 86c37e5

File tree

132 files changed

+17666
-1907
lines changed

Some content is hidden

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

132 files changed

+17666
-1907
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ download-fabric:
4141
unit-tests:
4242
@go test -cover $(shell go list ./... | grep -v '/integration/')
4343
cd integration/nwo/; go test -cover ./...
44-
cd token/services/identity/storage/kvs/hashicorp/; go test -cover ./...
44+
cd token/services/storage/db/kvs/hashicorp/; go test -cover ./...
4545

4646
.PHONY: unit-tests-race
4747
unit-tests-race:
@@ -97,7 +97,7 @@ integration-tests-dvp-dlog:
9797
tidy:
9898
@go mod tidy
9999
cd tools; go mod tidy
100-
cd token/services/identity/storage/kvs/hashicorp; go mod tidy
100+
cd token/services/storage/db/kvs/hashicorp; go mod tidy
101101

102102
.PHONY: clean
103103
clean:

docs/driverapi.md

Lines changed: 5 additions & 377 deletions
Large diffs are not rendered by default.

docs/drivers/dlogwogh.md

Lines changed: 356 additions & 0 deletions
Large diffs are not rendered by default.

docs/drivers/fabtoken.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# FabToken
2+
3+
FabToken is a straightforward implementation of the Driver API.
4+
It prioritizes simplicity over privacy, storing all token transaction details openly on the ledger for anyone with access to view ownership and activity.
5+
FabToken exclusively supports long-term identities based on a standard X.509 certificate scheme,
6+
which reveals the owner's enrollment ID in plain text.
7+
Tokens are directly represented on the ledger as JSON-formatted data based on the `token.Token` structure.
8+
The `Owner` field of this structure stores the identity information.
9+
The `Identity Service` handles the encoding/decoding of this field.
10+
11+
## Security
12+
13+
`FabToken` does not provide privacy for tokens or identities.
14+
The validator guarantees the following:
15+
* **Issuer Authorization**: Only issuers listed in the public parameters can issue tokens.
16+
* **Auditor Authorization**: Only auditors listed in the public parameters can audit transactions.
17+
* **Owner Authorization**: Only legitimate owners can spend their tokens.
18+
* **Value Preservation**: In a transfer, the sum of inputs matches the sum of outputs.

docs/services.md

Lines changed: 8 additions & 364 deletions
Large diffs are not rendered by default.

docs/services/identity.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# Identity Service
2+
3+
The **Identity Service** (`token/services/identity`) provides a unified interface for managing identities, signatures, and verification within the Fabric Token SDK.
4+
It abstracts the underlying cryptographic details, allowing the SDK to support multiple identity types (e.g., X.509, Idemix) and different storage backends seamlessly.
5+
6+
This service is a fundamental component used by token drivers and other services (like the Token Transaction (TTX) service) to handle:
7+
* **Signatures**: Generating and verifying signatures for transactions.
8+
* **Identity Resolution**: resolving long-term identities to ephemeral identities and vice-versa.
9+
* **Auditability**: Managing audit information to reveal the enrollment ID behind an anonymous identity (if allowed).
10+
* **Role Management**: Handling identities for different roles (Issuer, Auditor, Owner, Certifier).
11+
12+
## Architecture
13+
14+
The Identity Service is designed to implement the **Driver API** interfaces defined in `token/driver/wallet.go`.
15+
This ensures that the token management system can interact with any identity implementation through a standard set of methods.
16+
17+
### Conceptual Metaphor
18+
19+
To better understand the components, imagine a **Corporate Security Department**:
20+
21+
* **Identity Service (The Department)**: The entire division responsible for security and access.
22+
* **Wallet Service (The Keymaster)**: Maintains a registry of all employees (Wallets) and the badges (Keys) they possess. It knows who has access to what.
23+
* **Identity Provider (The Passport Office)**: Verifies identities. It checks if a badge is authentic and extracts information from it (Project ID, Department ID).
24+
* **Roles (Job Titles)**: Groups of employees with similar access rights (e.g., "Auditors" have special keys to view records, "Issuers" have keys to create assets).
25+
* **Key Managers (The Badge Makers)**: The specific machines or protocols used to create the badges (e.g., one machine makes standard plastic cards (X.509), another makes high-tech smart cards (Idemix)).
26+
27+
### Component Mapping
28+
29+
Here is how the service components map to the Driver API:
30+
31+
| Component | Implements Driver Interface | Description |
32+
|:-----------------------|:----------------------------|:------------------------------------------------------|
33+
| `identity.Provider` | `driver.IdentityProvider` | Core identity management & verification. |
34+
| `wallet.Service` | `driver.WalletService` | Registry for all wallets (Owner, Issuer, etc.). |
35+
| `role.LongTermOwnerWallet` | `driver.OwnerWallet` | Long Term Identity-based Onwer wallet functionality. |
36+
| `role.AnonymousOwnerWallet` | `driver.OwnerWallet` | Anonymous Identity-based Onwer wallet functionality. |
37+
| `role.IssuerWallet` | `driver.IssuerWallet` | Issuer wallet functionality. |
38+
| `role.AuditorWallet` | `driver.AuditorWallet` | Auditor wallet functionality. |
39+
| `role.CertifierWallet` | `driver.CertifierWallet` | Certifier wallet functionality. |
40+
41+
### Component Interaction Diagram
42+
43+
```mermaid
44+
classDiagram
45+
direction TB
46+
%% Driver Interfaces
47+
class IdentityProvider {
48+
<<interface>>
49+
+GetSigner()
50+
+GetAuditInfo()
51+
+IsMe()
52+
}
53+
class WalletService {
54+
<<interface>>
55+
+OwnerWallet()
56+
+IssuerWallet()
57+
+RegisterRecipientIdentity()
58+
}
59+
60+
%% Concrete Implementations
61+
class identity.Provider {
62+
-Storage
63+
-Deserializers
64+
-SignerCache
65+
}
66+
class wallet.Service {
67+
-RoleRegistry
68+
-IdentityProvider
69+
-OwnerWallet
70+
-IssuerWallet
71+
-AuditorWallet
72+
-CertifierWallet
73+
}
74+
class role.Role {
75+
-LocalMembership
76+
+GetIdentityInfo()
77+
}
78+
class membership.KeyManagerProvider {
79+
<<interface>>
80+
+Get() KeyManager
81+
}
82+
83+
identity.Provider ..|> IdentityProvider : Implements
84+
wallet.Service ..|> WalletService : Implements
85+
wallet.Service --> identity.Provider : Uses
86+
wallet.Service --> role.Role : Uses (via RoleRegistry)
87+
role.Role --> membership.KeyManagerProvider : Uses (via LocalMembership)
88+
89+
note for identity.Provider "Handles low-level crypto\nand identity verification"
90+
note for wallet.Service "High-level management\nof wallets and roles"
91+
```
92+
93+
### LocalMembership
94+
95+
The `LocalMembership` component (`token/services/identity/membership`) plays a pivotal role in managing local identities for a specific role (e.g., Owner, Issuer).
96+
97+
* **Binding**: Each instance is bound to a list of **Key Managers**.
98+
* **Identity Wrapping**: When a Key Manager generates an identity (based on the configuration), `LocalMembership` automatically wraps it using `WrapWithType`.
99+
This ensures that the generated identity carries the correct type information required by the system (as defined in `token/services/identity/typed.go`).
100+
* **Role Implementation**: `LocalMembership` serves as the foundational implementation for `role.Role`.
101+
When you interact with a Role to resolve an identity or sign a transaction, you are effectively delegating to the underlying `LocalMembership`.
102+
103+
### Example: Wiring Services
104+
105+
The following example demonstrates how these services are instantiated and wired together, as seen in the ZKATDLog driver:
106+
107+
```go
108+
func (d *Base) NewWalletService(...) (*wallet.Service, error) {
109+
// 1. Create Identity Provider
110+
identityProvider := identity.NewProvider(...)
111+
112+
// 2. Initialize Membership Role Factory
113+
roleFactory := membership.NewRoleFactory(...)
114+
115+
// 3. Configure Key Managers (e.g. Idemix and X.509 for Owner role)
116+
// we have one key manager to handle fabtoken tokens and one for each idemix issuer public key in the public parameters
117+
kmps := make([]membership.KeyManagerProvider, 0)
118+
// ... add Idemix Key Manager Providers ...
119+
kmps = append(kmps, x509.NewKeyManagerProvider(...))
120+
121+
// 4. Create and Register Roles
122+
roles := role.NewRoles()
123+
124+
// Owner Role (with anonymous identities)
125+
ownerRole, err := roleFactory.NewRole(identity.OwnerRole, true, nil, kmps...)
126+
roles.Register(identity.OwnerRole, ownerRole)
127+
128+
// Issuer Role (no anonymous identities)
129+
issuerRole, err := roleFactory.NewRole(identity.IssuerRole, false, pp.Issuers(), x509.NewKeyManagerProvider(...))
130+
roles.Register(identity.IssuerRole, issuerRole)
131+
132+
// ... Register Auditor and Certifier roles ...
133+
134+
// 5. Create Wallet Service with the registered roles
135+
return wallet.NewService(
136+
logger,
137+
identityProvider,
138+
deserializer,
139+
// Convert the roles registry into the format expected by the wallet service
140+
wallet.Convert(roles.Registries(...)),
141+
), nil
142+
}
143+
```
144+
145+
## Identity Types
146+
147+
The Identity Service leverages a wrapper called **TypedIdentity** to support various identity schemes uniformly.
148+
This allows the SDK to be extensible and capable of handling different cryptographic requirements.
149+
150+
### TypedIdentity
151+
152+
`TypedIdentity` (defined in `token/services/identity/typed.go`) acts as a generic container.
153+
It wraps the raw identity bytes with a type label, enabling the system to verify deserializers and process signatures correctly without hardcoding implementation details.
154+
* **Structure**: Contains a `Type` (string) and the `Identity` (raw bytes).
155+
156+
### Default Key Managers
157+
158+
The identity service includes two primary implementations for concrete identities:
159+
160+
#### 1. X.509
161+
Standard PKIX identities.
162+
* **Transparency**: Verification reveals the identity of the signer.
163+
* **Usage**: Ideal for infrastructure components (nodes, services) or scenarios where anonymity is not required.
164+
* **Implementation**: `token/services/identity/x509`.
165+
166+
#### 2. Idemix (Identity Mixer)
167+
Advanced identity encryption based on Zero-Knowledge Proofs (ZKP).
168+
* **Anonymity**: Users can prove they hold a valid credential without revealing their actual identity.
169+
* **Unlinkability**: Different transactions from the same user appear uncorrelated.
170+
* **Auditability**: Includes "audit info" facilitating regulatory compliance by allowing authorized auditors to reveal the identity.
171+
* **Implementation**: `token/services/identity/idemix`.
172+
173+
### Other Identity Types
174+
175+
The architecture supports specialized identity types for complex use cases:
176+
177+
#### Multisig
178+
Located in `token/services/identity/multisig`.
179+
* **Concept**: An identity that wraps multiple sub-identities.
180+
* **Usage**: Useful for requiring multiple signatures or representing a group of parties.
181+
* **Auditability**: Aggregates audit information for all underlying identities.
182+
183+
#### HTLC (Hashed Time Lock Contract)
184+
Located in `token/services/identity/interop/htlc`.
185+
* **Concept**: A script-based identity used primarily for interoperability mechanisms like atomic swaps.
186+
* **Structure**: Encapsulates a **Sender** identity, a **Recipient** identity, hash lock information, and a timeout.
187+
* **Behavior**: Validation involves satisfying the script conditions (e.g., providing the hash preimage).

docs/services/network.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## The Network Service
2+
3+
The `network` service, located under `token/services/network`, provides other services with a consistent and predictable interface to the backend (e.g., Fabric).
4+
Internally, the network service mirrors the structure of the Token API, consisting of a `Provider` of network instances and the `Network` instances themselves.
5+
6+
The network service architecture is depicted below:
7+
8+
![network_service.png](../imgs/network_service.png)
9+
10+
The Fabric-based network implementation utilizes the Fabric Smart Client for configuration and operations, including chaincode queries and transaction broadcasting.
11+
12+
During bootstrap, the Token SDK processes the TMS defined in the configuration.
13+
For each TMS, the network provider retrieves the network instance corresponding to the `network` and `channel` specified in the TMS ID.
14+
Failure to retrieve the network instance results in a bootstrap failure.
15+
Upon success, the `Connect` function on the `Network` instance is invoked with the target namespace.
16+
This function establishes a connection to the backend, enabling the Token SDK to receive updates on public parameters and transaction finality.
17+
18+
When `Connect` is called, the Fabric network implementation establishes two `Fabric Delivery` streams to receive committed blocks:
19+
- One stream is used to analyze transactions that update the public parameters.
20+
More specifically, for each transaction in a block, the parser checks if the RW set contains a write whose key is the `setup key`.
21+
The setup key is set as `\x00seU+0000`. If such a key is found in a valid transaction, then the listener added upon calling `Connect` does the following:
22+
- It invokes the `Update` function of the TMS provider passing the TMS ID and the byte representation of the new public parameters.
23+
The function works as follows: if a TMS instance with the passed ID does not exist, it creates one.
24+
If a TMS with that ID already exists, then:
25+
- A new instance of TMS is created with the new public parameters.
26+
- If the previous step succeeds, then the `Done` function on the old TMS instance is invoked to release all allocated resources.
27+
- If the above step succeeds, then the public parameters are appended to the `PublicParameters` table.
28+
- The other stream is dedicated to transaction finality. Services can add listeners to the `Network` instance to listen for the finality of specific transactions.
29+
The `ttx` service and the `audit` service add a listener when a transaction has reached the point of being ready to be submitted to the ordering service.
30+
(For more information, look at the sections dedicated to these services). Both services use the same listener.
31+
This listener performs the following actions upon notification of the finality of a transaction:
32+
- If the transaction's status is valid, then the token request's hash contained in the transaction is matched against the hash of the token request stored in the database.
33+
If they match, then the `Tokens` table is updated by inserting the new tokens and marking the spent tokens as deleted.
34+
The corresponding token request in the `Requests` table is marked as `Valid` with a change of the status field.
35+
- If the transaction's status is invalid, then the corresponding token request in the `Requests` table is marked as `Invalid` or `Deleted`.
36+
In all other cases, an error is returned.
37+

0 commit comments

Comments
 (0)