async Task <IssuanceDetailsDto> IssueIdpAttributesAsRoot( string issuer, ConfidentialAccount confidentialAccount, Identity identity, IEnumerable <AttributeIssuanceDetails> attributeIssuanceDetails, AccountDescriptor account, StatePersistency statePersistency) { IssuanceDetailsDto issuanceDetails = new IssuanceDetailsDto(); IEnumerable <IdentitiesScheme> identitiesSchemes = _dataAccessService.GetAttributesSchemeByIssuer(issuer, true); var rootAttributeDetails = attributeIssuanceDetails.First(a => a.Definition.IsRoot); byte[] rootAssetId = await _assetsService.GenerateAssetId(rootAttributeDetails.Definition.SchemeName, rootAttributeDetails.Value.Value, issuer).ConfigureAwait(false); IdentityAttribute rootAttribute = identity.Attributes.FirstOrDefault(a => a.AttributeName == rootAttributeDetails.Definition.AttributeName); statePersistency.TransactionsService.IssueBlindedAsset(rootAssetId, 0UL.ToByteArray(32), out byte[] originatingCommitment); _dataAccessService.UpdateIdentityAttributeCommitment(rootAttribute.AttributeId, originatingCommitment); issuanceDetails.AssociatedAttributes = await IssueAssociatedAttributes( attributeIssuanceDetails.Where(a => !a.Definition.IsRoot) .ToDictionary(d => identity.Attributes.First(a => a.AttributeName == d.Definition.AttributeName).AttributeId, d => d), statePersistency.TransactionsService, issuer, rootAssetId).ConfigureAwait(false); var packet = statePersistency.TransactionsService.TransferAssetToUtxo(rootAssetId, confidentialAccount); if (packet == null) { _logger.Error($"[{account.AccountId}]: failed to transfer Root Attribute"); throw new RootAttributeTransferFailedException(); } issuanceDetails.RootAttribute = new IssuanceDetailsDto.IssuanceDetailsRoot { AttributeName = rootAttribute.AttributeName, OriginatingCommitment = packet.SurjectionProof.AssetCommitments[0].ToHexString(), AssetCommitment = packet.TransferredAsset.AssetCommitment.ToHexString(), SurjectionProof = $"{packet.SurjectionProof.Rs.E.ToHexString()}{packet.SurjectionProof.Rs.S[0].ToHexString()}" }; return(issuanceDetails); }
public async Task <ActionResult <IEnumerable <AttributeValue> > > IssueIdpAttributes(string issuer, [FromBody] IssueAttributesRequestDTO request) { if (request is null) { throw new ArgumentNullException(nameof(request)); } AccountDescriptor account = _accountsService.GetByPublicKey(issuer.HexStringToByteArray()); StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(account.AccountId); IEnumerable <AttributeDefinition> attributeDefinitions = _dataAccessService.GetAttributesSchemeByIssuer(issuer, true) .Select(a => new AttributeDefinition { SchemeId = a.IdentitiesSchemeId, AttributeName = a.AttributeName, SchemeName = a.AttributeSchemeName, Alias = a.Alias, Description = a.Description, IsActive = a.IsActive, IsRoot = a.CanBeRoot }); if (!attributeDefinitions.Any(a => a.IsRoot)) { throw new NoRootAttributeSchemeDefinedException(issuer); } var issuanceInputDetails = GetValidatedIssuanceDetails(request, attributeDefinitions); Identity identity = CreateIdentityInDb(account, issuanceInputDetails); IssuanceDetailsDto issuanceDetails; if (!string.IsNullOrEmpty(request.PublicSpendKey) && !string.IsNullOrEmpty(request.PublicViewKey)) { ConfidentialAccount targetAccount = new ConfidentialAccount { PublicSpendKey = request.PublicSpendKey.HexStringToByteArray(), PublicViewKey = request.PublicViewKey.HexStringToByteArray() }; issuanceDetails = await IssueIdpAttributesAsRoot(issuer, request.Protection, identity, issuanceInputDetails, account, targetAccount, statePersistency).ConfigureAwait(false); } else { issuanceDetails = await IssueIdpAttributesAsAssociated(issuer, identity, issuanceInputDetails, statePersistency).ConfigureAwait(false); } await _idenitiesHubContext.Clients.Group(account.AccountId.ToString()).SendAsync("RequestForIssuance", issuanceDetails); IIntegrationIdP integrationService = GetIntegrationService(account.AccountId); if (integrationService != null) { IssuanceDetails issuanceIntegration = new IssuanceDetails { RootAttribute = new IssuanceDetails.IssuanceDetailsRoot { AttributeName = issuanceDetails.RootAttribute.AttributeName, AssetCommitment = issuanceDetails.RootAttribute.AssetCommitment.HexStringToByteArray(), OriginatingCommitment = issuanceDetails.RootAttribute.OriginatingCommitment.HexStringToByteArray(), SurjectionProof = issuanceDetails.RootAttribute.SurjectionProof.HexStringToByteArray() }, AssociatedAttributes = issuanceDetails.AssociatedAttributes .Select(a => new IssuanceDetails.IssuanceDetailsAssociated { AttributeName = a.AttributeName, AssetCommitment = a.AssetCommitment.HexStringToByteArray(), BindingToRootCommitment = a.BindingToRootCommitment.HexStringToByteArray() }).ToList() }; integrationService.IssueAttributes(account.AccountId, issuanceIntegration); } var attributeValues = FillAttributeValues(request.Attributes, attributeDefinitions); return(Ok(attributeValues)); #region Internal Functions IReadOnlyCollection <AttributeValue> FillAttributeValues(Dictionary <string, IssueAttributesRequestDTO.AttributeValue> attributes, IEnumerable <AttributeDefinition> attributeDefinitions) { List <AttributeValue> attributeValues = new List <AttributeValue>(); var protectionAttrDefinition = attributeDefinitions.FirstOrDefault(a => a.SchemeName == AttributesSchemes.ATTR_SCHEME_NAME_PASSWORD); foreach (var attributeName in attributes.Keys.Where(a => protectionAttrDefinition?.AttributeName != a)) { string content = attributes[attributeName].Value; AttributeValue attributeValue = new AttributeValue { Value = content, Definition = attributeDefinitions.FirstOrDefault(d => d.AttributeName == attributeName) }; attributeValues.Add(attributeValue); } return(new ReadOnlyCollection <AttributeValue>(attributeValues)); } async Task <IssuanceDetailsDto> IssueIdpAttributesAsRoot( string issuer, IssuanceProtection protection, Identity identity, IEnumerable <AttributeIssuanceDetails> attributeIssuanceDetails, AccountDescriptor account, ConfidentialAccount targetAccount, StatePersistency statePersistency) { IssuanceDetailsDto issuanceDetails = new IssuanceDetailsDto(); IEnumerable <IdentitiesScheme> identitiesSchemes = _dataAccessService.GetAttributesSchemeByIssuer(issuer, true); var rootAttributeDetails = attributeIssuanceDetails.First(a => a.Definition.IsRoot); byte[] rootAssetId = await _assetsService.GenerateAssetId(rootAttributeDetails.Definition.SchemeName, rootAttributeDetails.Value.Value, issuer).ConfigureAwait(false); IdentityAttribute rootAttribute = identity.Attributes.FirstOrDefault(a => a.AttributeName == rootAttributeDetails.Definition.AttributeName); if (!CreateRootAttributeIfNeeded(statePersistency, rootAttribute, rootAssetId)) { var protectionAttribute = identity.Attributes.FirstOrDefault(a => a.AttributeName == AttributesSchemes.ATTR_SCHEME_NAME_PASSWORD); bool res = VerifyProtectionAttribute(protectionAttribute, protection.SignatureE.HexStringToByteArray(), protection.SignatureS.HexStringToByteArray(), protection.SessionCommitment.HexStringToByteArray()); if (!res) { _logger.Warning($"[{account.AccountId}]: Failed to verify Surjection Proofs of the Protection Attribute"); throw new ProtectionAttributeVerificationFailedException(); } } else { issuanceDetails.AssociatedAttributes = await IssueAssociatedAttributes( attributeIssuanceDetails.Where(a => !a.Definition.IsRoot) .ToDictionary(d => identity.Attributes.First(a => a.AttributeName == d.Definition.AttributeName).AttributeId, d => d), statePersistency.TransactionsService, issuer, rootAssetId).ConfigureAwait(false); } var packet = TransferAssetToUtxo(statePersistency.TransactionsService, targetAccount, rootAssetId); if (packet == null) { _logger.Error($"[{account.AccountId}]: failed to transfer Root Attribute"); throw new RootAttributeTransferFailedException(); } _dataAccessService.AddOrUpdateIdentityTarget(identity.IdentityId, targetAccount.PublicSpendKey.ToHexString(), targetAccount.PublicViewKey.ToHexString()); issuanceDetails.RootAttribute = new IssuanceDetailsDto.IssuanceDetailsRoot { AttributeName = rootAttribute.AttributeName, OriginatingCommitment = packet.SurjectionProof.AssetCommitments[0].ToHexString(), AssetCommitment = packet.TransferredAsset.AssetCommitment.ToHexString(), SurjectionProof = $"{packet.SurjectionProof.Rs.E.ToHexString()}{packet.SurjectionProof.Rs.S[0].ToHexString()}" }; return(issuanceDetails); } async Task <IssuanceDetailsDto> IssueIdpAttributesAsAssociated( string issuer, Identity identity, IEnumerable <AttributeIssuanceDetails> attributeIssuanceDetails, StatePersistency statePersistency) { IssuanceDetailsDto issuanceDetails = new IssuanceDetailsDto(); IdentitiesScheme rootScheme = _dataAccessService.GetRootIdentityScheme(issuer); IEnumerable <IdentitiesScheme> identitiesSchemes = _dataAccessService.GetAttributesSchemeByIssuer(issuer, true); var rootAttributeDetails = attributeIssuanceDetails.First(a => a.Definition.IsRoot); var packet = await IssueAssociatedAttribute( rootScheme.AttributeSchemeName, rootAttributeDetails.Value.Value, rootAttributeDetails.Value.BlindingPointValue, rootAttributeDetails.Value.BlindingPointRoot, issuer, statePersistency.TransactionsService).ConfigureAwait(false); _dataAccessService.UpdateIdentityAttributeCommitment(identity.Attributes.FirstOrDefault(a => a.AttributeName == rootScheme.AttributeName).AttributeId, packet.AssetCommitment); byte[] rootAssetId = _assetsService.GenerateAssetId(rootScheme.IdentitiesSchemeId, rootAttributeDetails.Value.Value); issuanceDetails.AssociatedAttributes = await IssueAssociatedAttributes( attributeIssuanceDetails .ToDictionary(d => identity.Attributes.First(a => a.AttributeName == d.Definition.AttributeName).AttributeId, d => d), statePersistency.TransactionsService, issuer, rootAssetId).ConfigureAwait(false); return(issuanceDetails); }