예제 #1
0
        public void UnregisterExecutionServices(long accountId)
        {
            _logger.Info($"[{accountId}]: Stopping services for account");

            if (_statePersistencyItems.ContainsKey(accountId))
            {
                StatePersistency persistency = _statePersistencyItems[accountId];
                persistency.CancellationTokenSource.Cancel();
                persistency.WalletSynchronizer.Dispose();

                _statePersistencyItems.Remove(accountId);
                persistency.TransactionsService = null;
                persistency.WalletSynchronizer  = null;
                persistency.ClientCryptoService = null;
            }
            else if (_utxoPersistencyItems.ContainsKey(accountId))
            {
                UtxoPersistency persistency = _utxoPersistencyItems[accountId];
                persistency.CancellationTokenSource.Cancel();
                persistency.WalletSynchronizer.Dispose();

                _utxoPersistencyItems.Remove(accountId);
                persistency.TransactionsService = null;
                persistency.WalletSynchronizer  = null;
                persistency.ClientCryptoService = null;
            }

            Clean(accountId);
        }
예제 #2
0
        public IActionResult ProcessRootIdentityRequest(string issuer, [FromBody] IdentityRequestDto identityRequest)
        {
            Account          identityProviderAccount = _accountsService.GetByPublicKey(issuer.HexStringToByteArray());
            StatePersistency statePersistency        = _executionContextManager.ResolveStateExecutionServices(identityProviderAccount.AccountId);

            Tuple <bool, bool> proceed = VerifyFaceImage(identityRequest.FaceImageContent, identityRequest.RootAttributeContent, issuer);

            if (proceed.Item1)
            {
                byte[] rootAssetId      = _assetsService.GenerateAssetId(AttributeType.IdCard, identityRequest.RootAttributeContent);
                byte[] faceImageAssetId = _assetsService.GenerateAssetId(AttributeType.PassportPhoto, identityRequest.FaceImageContent);

                ProcessIssuingAssociatedAttributes(identityRequest, statePersistency.TransactionsService, rootAssetId, faceImageAssetId);

                return(TransferAssetToUtxo(statePersistency.TransactionsService, new ConfidentialAccount {
                    PublicSpendKey = identityRequest.RequesterPublicSpendKey.HexStringToByteArray(), PublicViewKey = identityRequest.RequesterPublicViewKey.HexStringToByteArray()
                }, rootAssetId));
            }
            else
            {
                if (!proceed.Item2)
                {
                    return(BadRequest(new { Message = $"Failed to find person with ID Card number {identityRequest.RootAttributeContent}" }));
                }

                return(BadRequest(new { Message = "Captured face does not match to registered one" }));
            }
        }
예제 #3
0
        public IActionResult UpdateEmployee(long accountId, [FromBody] EmployeeDto employee)
        {
            _dataAccessService.UpdateSpEmployeeCategory(accountId, employee.EmployeeId, employee.GroupId);
            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(accountId);

            statePersistency.TransactionsService.IssueCancelEmployeeRecord(employee.RegistrationCommitment.HexStringToByteArray());

            return(Ok(employee));
        }
예제 #4
0
        public IActionResult DeleteAllowedSigner(long spId, long allowedSignerId)
        {
            long       documentId = _dataAccessService.RemoveSpDocumentAllowedSigner(spId, allowedSignerId);
            SpDocument document   = _dataAccessService.GetSpDocument(spId, documentId);

            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(spId);

            statePersistency.TransactionsService.IssueDocumentRecord(document.Hash.HexStringToByteArray(), document.AllowedSigners.Select(s => s.GroupCommitment.HexStringToByteArray()).ToArray());

            return(Ok());
        }
예제 #5
0
        public IActionResult AddDocument(long spId, [FromBody] DocumentDto documentDto)
        {
            documentDto.DocumentId = _dataAccessService.AddSpDocument(spId, documentDto.DocumentName, documentDto.Hash);
            SpDocument document = _dataAccessService.GetSpDocument(spId, documentDto.DocumentId);

            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(spId);

            statePersistency.TransactionsService.IssueDocumentRecord(document.Hash.HexStringToByteArray(), document.AllowedSigners?.Select(s => s.GroupCommitment.HexStringToByteArray()).ToArray());

            return(Ok(documentDto));
        }
예제 #6
0
        public IActionResult DeleteEmployee(long accountId, long employeeId)
        {
            SpEmployee       spEmployee       = _dataAccessService.RemoveSpEmployee(accountId, employeeId);
            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(accountId);

            if (!string.IsNullOrEmpty(spEmployee.RegistrationCommitment))
            {
                statePersistency.TransactionsService.IssueCancelEmployeeRecord(spEmployee.RegistrationCommitment.HexStringToByteArray());
            }

            return(Ok());
        }
예제 #7
0
        public IActionResult SendAssetIdNew([FromBody] AttributeTransferDetails attributeTransferDetails)
        {
            ulong accountId = ulong.Parse(User.Identity.Name, CultureInfo.InvariantCulture);

            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(accountId);

            return(Ok(statePersistency.TransactionsService.TransferAssetToUtxo(_assetsService.GenerateAssetId(AttributeType.IdCard, attributeTransferDetails.Id),
                                                                               new ConfidentialAccount
            {
                PublicSpendKey = attributeTransferDetails.PublicSpendKey.HexStringToByteArray(),
                PublicViewKey = attributeTransferDetails.PublicViewKey.HexStringToByteArray()
            })));
        }
예제 #8
0
        public IActionResult DeleteAllowedSigner(ulong allowedSignerId)
        {
            ulong accountId = ulong.Parse(User.Identity.Name, CultureInfo.InvariantCulture);

            ulong      documentId = _dataAccessService.RemoveSpDocumentAllowedSigner(accountId, allowedSignerId);
            SpDocument document   = _dataAccessService.GetSpDocument(accountId, documentId);

            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(accountId);

            statePersistency.TransactionsService.IssueDocumentRecord(document.Hash.HexStringToByteArray(), document.AllowedSigners.Select(s => s.GroupCommitment.HexStringToByteArray()).ToArray());

            return(Ok());
        }
예제 #9
0
        public IActionResult AddDocument([FromBody] DocumentDto documentDto)
        {
            ulong accountId = ulong.Parse(User.Identity.Name, CultureInfo.InvariantCulture);

            documentDto.DocumentId = _dataAccessService.AddSpDocument(accountId, documentDto.DocumentName, documentDto.Hash);
            SpDocument document = _dataAccessService.GetSpDocument(accountId, documentDto.DocumentId);

            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(accountId);

            statePersistency.TransactionsService.IssueDocumentRecord(document.Hash.HexStringToByteArray(), document.AllowedSigners?.Select(s => s.GroupCommitment.HexStringToByteArray()).ToArray());

            return(Ok(documentDto));
        }
예제 #10
0
        public async Task <IActionResult> AddAllowedSigner(long spId, long documentId, [FromBody] AllowedSignerDto allowedSigner)
        {
            byte[] groupAssetId = await _assetsService.GenerateAssetId(AttributesSchemes.ATTR_SCHEME_NAME_EMPLOYEEGROUP, allowedSigner.GroupOwner + allowedSigner.GroupName, allowedSigner.GroupOwner).ConfigureAwait(false);

            byte[] blindingFactor  = ConfidentialAssetsHelper.GetRandomSeed();
            byte[] groupCommitment = ConfidentialAssetsHelper.GetAssetCommitment(blindingFactor, groupAssetId);

            allowedSigner.AllowedSignerId = _dataAccessService.AddSpDocumentAllowedSigner(spId, documentId, allowedSigner.GroupOwner, allowedSigner.GroupName, groupCommitment.ToHexString(), blindingFactor.ToHexString());

            SpDocument document = _dataAccessService.GetSpDocument(spId, documentId);

            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(spId);

            statePersistency.TransactionsService.IssueDocumentRecord(document.Hash.HexStringToByteArray(), document.AllowedSigners.Select(s => s.GroupCommitment.HexStringToByteArray()).ToArray());

            return(Ok(allowedSigner));
        }
예제 #11
0
        public IActionResult CreateIdentity([FromBody] IdentityDto identity)
        {
            ulong accountId = ulong.Parse(User.Identity.Name, CultureInfo.InvariantCulture);

            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(accountId);
            Account          account          = _accountsService.GetById(accountId);

            byte[] assetId = _assetsService.GenerateAssetId((AttributeType)identity.RootAttribute.AttributeType, identity.RootAttribute.Content);
            statePersistency.TransactionsService.IssueBlindedAsset(assetId, 0UL.ToByteArray(32), out byte[] originatingCommitment);
            identity.RootAttribute.OriginatingCommitment = originatingCommitment.ToHexString();

            Identity identityDb = _externalDataAccessService.CreateIdentity(accountId, identity.Description, new IdentityAttribute {
                AttributeType = AttributeType.IdCard, Content = identity.RootAttribute.Content, Subject = ClaimSubject.User, Commitment = originatingCommitment
            });

            identity.Id = identityDb.IdentityId.ToString(CultureInfo.InvariantCulture);

            string imageContent = null;

            foreach (var identityAttributeDto in identity.AssociatedAttributes)
            {
                IdentityAttribute identityAttribute = new IdentityAttribute
                {
                    AttributeType = (AttributeType)identityAttributeDto.AttributeType,
                    Content       = identityAttributeDto.Content,
                    Subject       = ClaimSubject.User
                };
                _externalDataAccessService.AddAssociatedIdentityAttribute(identityDb.IdentityId, ref identityAttribute);

                if (((AttributeType)identityAttributeDto.AttributeType) == AttributeType.PassportPhoto)
                {
                    imageContent = identityAttributeDto.Content;
                }
            }

            if (!string.IsNullOrEmpty(identity.RootAttribute.Content) && !string.IsNullOrEmpty(imageContent))
            {
                $"{Request.Scheme}://{Request.Host.ToUriComponent()}/biometric/".AppendPathSegment("RegisterPerson").PostJsonAsync(new BiometricPersonDataDto {
                    Requester = account.PublicSpendKey.ToHexString(), PersonData = identity.RootAttribute.Content, ImageString = imageContent
                });
            }

            _hubContext.Clients.Group(User.Identity.Name).SendAsync("PushIdentity", identity);

            return(Ok());
        }
예제 #12
0
        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);
        }
예제 #13
0
        public IActionResult AddAllowedSigner(ulong documentId, [FromBody] AllowedSignerDto allowedSigner)
        {
            ulong accountId = ulong.Parse(User.Identity.Name, CultureInfo.InvariantCulture);

            byte[] groupAssetId    = _assetsService.GenerateAssetId(AttributeType.EmployeeGroup, allowedSigner.GroupOwner + allowedSigner.GroupName);
            byte[] blindingFactor  = ConfidentialAssetsHelper.GetRandomSeed();
            byte[] groupCommitment = ConfidentialAssetsHelper.GetAssetCommitment(groupAssetId, blindingFactor);

            allowedSigner.AllowedSignerId = _dataAccessService.AddSpDocumentAllowedSigner(accountId, documentId, allowedSigner.GroupOwner, allowedSigner.GroupName, groupCommitment.ToHexString(), blindingFactor.ToHexString());

            SpDocument document = _dataAccessService.GetSpDocument(accountId, documentId);

            StatePersistency statePersistency = _executionContextManager.ResolveStateExecutionServices(accountId);

            statePersistency.TransactionsService.IssueDocumentRecord(document.Hash.HexStringToByteArray(), document.AllowedSigners.Select(s => s.GroupCommitment.HexStringToByteArray()).ToArray());

            return(Ok(allowedSigner));
        }
예제 #14
0
        public void InitializeStateExecutionServices(long accountId, byte[] secretKey, Func <long, IStateTransactionsService, IStateClientCryptoService, CancellationToken, IUpdater> updaterFactory = null)
        {
            lock (_statePersistencyItems)
            {
                if (_statePersistencyItems.ContainsKey(accountId))
                {
                    _logger.Info($"[{accountId}]: Account with id {accountId} already registered at StatePersistency");
                    return;
                }

                _logger.Info($"[{accountId}]: {nameof(InitializeStateExecutionServices)} for account with id {accountId}");

                try
                {
                    IWitnessPackagesProvider  packetsProvider       = _witnessPackagesProviderRepository.GetInstance(_restApiConfiguration.WitnessProviderName);
                    IStateTransactionsService transactionsService   = ActivatorUtilities.CreateInstance <StateTransactionsService>(_serviceProvider);
                    IStateClientCryptoService clientCryptoService   = ActivatorUtilities.CreateInstance <StateClientCryptoService>(_serviceProvider);
                    IWalletSynchronizer       walletSynchronizer    = ActivatorUtilities.CreateInstance <StateWalletSynchronizer>(_serviceProvider);
                    StatePacketsExtractor     statePacketsExtractor = ActivatorUtilities.CreateInstance <StatePacketsExtractor>(_serviceProvider);

                    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

                    packetsProvider.Initialize(accountId, cancellationTokenSource.Token);
                    clientCryptoService.Initialize(secretKey);
                    transactionsService.AccountId = accountId;
                    ulong lastBlockHeight = AsyncUtil.RunSync(() => _gatewayService.GetLastBlockHeight(ConfidentialAssetsHelper.GetPublicKey(Ed25519.SecretKeyFromSeed(secretKey))));
                    transactionsService.Initialize(clientCryptoService, lastBlockHeight);
                    transactionsService.PipeOutTransactions.LinkTo(_gatewayService.PipeInTransactions);
                    statePacketsExtractor.Initialize(clientCryptoService);
                    statePacketsExtractor.AccountId = accountId;

                    IUpdater updater = updaterFactory != null?updaterFactory(accountId, transactionsService, clientCryptoService, cancellationTokenSource.Token) : CreateStateUpdater(accountId, transactionsService, clientCryptoService, cancellationTokenSource.Token);

                    walletSynchronizer.Initialize(accountId, clientCryptoService);

                    packetsProvider.PipeOut.LinkTo(statePacketsExtractor.PipeIn);
                    statePacketsExtractor.PipeOutPackets.LinkTo(walletSynchronizer.PipeInPackets);
                    statePacketsExtractor.PipeOutProcessed.LinkTo(walletSynchronizer.PipeInPackage);

                    foreach (var externalUpdater in _externalUpdatersRepository.GetInstances())
                    {
                        externalUpdater.Initialize(accountId);
                    }

                    walletSynchronizer.PipeOutPackets.LinkTo(
                        new ActionBlock <PacketBase>(async p =>
                    {
                        var tasks = new List <Task>
                        {
                            updater.PipeIn.SendAsync(p)
                        };

                        foreach (var externalUpdater in _externalUpdatersRepository.GetInstances())
                        {
                            tasks.Add(externalUpdater.PipeIn.SendAsync(p));
                        }

                        await Task.WhenAll(tasks).ConfigureAwait(false);
                    }));

                    packetsProvider.Start();

                    var state = new StatePersistency
                    {
                        AccountId               = accountId,
                        PacketsProvider         = packetsProvider,
                        TransactionsService     = transactionsService,
                        PacketsExtractor        = statePacketsExtractor,
                        ClientCryptoService     = clientCryptoService,
                        WalletSynchronizer      = walletSynchronizer,
                        CancellationTokenSource = cancellationTokenSource
                    };

                    _statePersistencyItems.Add(accountId, state);
                }
                catch (Exception ex)
                {
                    _logger.Error($"[{accountId}]: Failure during {nameof(InitializeStateExecutionServices)} for account with id {accountId}", ex);
                    throw;
                }
            }
        }
예제 #15
0
        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);
            }