private async Task VerifyProofToAssociatedAttributeKnowledge(UniversalProofs universalProofs, string schemeName) { AttributeProofs attr = universalProofs.IssuersAttributes?.FirstOrDefault(a => a.Issuer.Equals(universalProofs.Issuer))?.Attributes.FirstOrDefault(a => a.SchemeName == schemeName); if (attr == null) { throw new AssociatedAttrProofsAreMissingException(schemeName); } if (attr.CommitmentProof.SurjectionProof.AssetCommitments.Length != attr.BindingProof.AssetCommitments.Length) { throw new AssociatedAttrProofsMalformedException(schemeName); } if (!ConfidentialAssetsHelper.VerifySurjectionProof(attr.CommitmentProof.SurjectionProof, attr.Commitment.ArraySegment.Array)) { throw new AssociatedAttrProofToValueKnowledgeIncorrectException(schemeName); } IKey commitmentKey = universalProofs.IssuersAttributes.FirstOrDefault(a => a.Issuer.Equals(universalProofs.Issuer))?.RootAttribute.Commitment; byte[] commitment = ConfidentialAssetsHelper.SumCommitments(commitmentKey.Value.Span, attr.Commitment.Value.Span); if (!ConfidentialAssetsHelper.VerifySurjectionProof(attr.BindingProof, commitment)) { throw new AssociatedAttrProofToBindingIncorrectException(schemeName); } (Memory <byte> issuanceCommitment, Memory <byte> commitmentToRoot)[] attrs = new (Memory <byte>, Memory <byte>)[attr.BindingProof.AssetCommitments.Length];
public IActionResult SendOnboardingWithValidationsRequest([FromBody] UserAttributeTransferWithValidationsDto userAttributeTransferWithValidations) { ulong accountId = ulong.Parse(User.Identity.Name, CultureInfo.InvariantCulture); bool res = false; UtxoPersistency utxoPersistency = _executionContextManager.ResolveUtxoExecutionServices(accountId); var rootAttribute = _dataAccessService.GetUserAttributes(accountId).FirstOrDefault(u => !u.IsOverriden && u.AttributeType == _identityAttributesService.GetRootAttributeType().Item1); string blindingFactorSeedString = $"{rootAttribute.Content}{userAttributeTransferWithValidations.Password}"; byte[] blindingFactorSeed = ConfidentialAssetsHelper.FastHash256(Encoding.ASCII.GetBytes(blindingFactorSeedString)); byte[] blindingFactor = ConfidentialAssetsHelper.ReduceScalar32(blindingFactorSeed); byte[] blindingPoint = ConfidentialAssetsHelper.GetPublicKey(blindingFactor); byte[] rootNonBlindedCommitment = ConfidentialAssetsHelper.GetNonblindedAssetCommitment(rootAttribute.AssetId); byte[] rootOriginatingCommitment = ConfidentialAssetsHelper.SumCommitments(rootNonBlindedCommitment, blindingPoint); byte[] target = userAttributeTransferWithValidations.UserAttributeTransfer.Target.HexStringToByteArray(); _dataAccessService.GetAccountId(target, out ulong spAccountId); AssociatedProofPreparation[] associatedProofPreparations = null; IEnumerable <SpIdenitityValidation> spIdenitityValidations = _dataAccessService.GetSpIdenitityValidations(spAccountId); if (spIdenitityValidations != null && spIdenitityValidations.Count() > 0) { associatedProofPreparations = new AssociatedProofPreparation[spIdenitityValidations.Count()]; var associatedAttributes = _dataAccessService.GetUserAssociatedAttributes(accountId); int index = 0; foreach (var validation in spIdenitityValidations) { string attrContent = associatedAttributes.FirstOrDefault(a => a.Item1 == validation.AttributeType)?.Item2 ?? string.Empty; byte[] groupId = _identityAttributesService.GetGroupId(validation.AttributeType); byte[] assetId = validation.AttributeType != AttributeType.DateOfBirth ? _assetsService.GenerateAssetId(validation.AttributeType, attrContent) : rootAttribute.AssetId; byte[] associatedBlindingFactor = validation.AttributeType != AttributeType.DateOfBirth ? ConfidentialAssetsHelper.GetRandomSeed() : null; byte[] associatedCommitment = validation.AttributeType != AttributeType.DateOfBirth ? ConfidentialAssetsHelper.GetAssetCommitment(assetId, associatedBlindingFactor) : null; byte[] associatedNonBlindedCommitment = ConfidentialAssetsHelper.GetNonblindedAssetCommitment(assetId); byte[] associatedOriginatingCommitment = ConfidentialAssetsHelper.SumCommitments(associatedNonBlindedCommitment, blindingPoint); AssociatedProofPreparation associatedProofPreparation = new AssociatedProofPreparation { GroupId = groupId, Commitment = associatedCommitment, CommitmentBlindingFactor = associatedBlindingFactor, OriginatingAssociatedCommitment = associatedOriginatingCommitment, OriginatingBlindingFactor = blindingFactor, OriginatingRootCommitment = rootOriginatingCommitment }; associatedProofPreparations[index++] = associatedProofPreparation; } } SendOnboardingRequest(userAttributeTransferWithValidations.UserAttributeTransfer, utxoPersistency.TransactionsService, associatedProofPreparations); return(Ok(res)); }
public async Task <IActionResult> RegisterPerson([FromBody] BiometricPersonDataDto biometricPersonData) { byte[] imageContent = null; _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}, {biometricPersonData.Images?.Count ?? -1} {nameof(biometricPersonData.Images)}"); Contract.Requires(biometricPersonData != null, nameof(biometricPersonData)); Contract.Requires(biometricPersonData.Images != null, $"{nameof(biometricPersonData)}.{nameof(biometricPersonData.Images)}"); Contract.Requires(biometricPersonData.Images.Count > 0, $"Count {nameof(biometricPersonData)}.{nameof(biometricPersonData.Images)} > 0"); foreach (var image in biometricPersonData.Images) { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}, {nameof(image.Key)}={image.Key}, image length: {image.Value?.Length ?? -1}"); } TaskCompletionSource <InherenceData> taskCompletionSource = _inherenceService.GetIdentityProofsAwaiter(biometricPersonData.SessionKey); InherenceData inherenceData; if (taskCompletionSource.Task.IsCompleted) { inherenceData = taskCompletionSource.Task.Result; } else { try { inherenceData = await taskCompletionSource.Task.TimeoutAfter(30000).ConfigureAwait(false); } catch (TimeoutException ex) { _logger.Error($"[{_inherenceService.AccountId}]: Identity Proofs not received for the SessionKey {biometricPersonData.SessionKey}", ex); return(BadRequest("Identity Proofs not received")); } catch (Exception ex) { _logger.Error($"[{_inherenceService.AccountId}]: Identity Proofs failed", ex); return(BadRequest($"Identity Proofs failed: {ex.Message}")); } finally { _inherenceService.RemoveIdentityProofsAwaiter(biometricPersonData.SessionKey); } } _inherenceService.RemoveIdentityProofsAwaiter(biometricPersonData.SessionKey); if (inherenceData == null) { _logger.Error($"[{_inherenceService.AccountId}]: Identity Proofs failed for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); return(BadRequest("Identity Proofs failed")); } _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(InherenceData)} with {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} obtained"); string registrationKey = inherenceData.RootRegistrationProof.AssetCommitments[0].ToHexString(); _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, root commitment is {inherenceData.AssetRootCommitment.ToHexString()} and registration key is {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} obtained"); string personGroupId = _portalConfiguration.DemoMode ? _portalConfiguration.FacePersonGroupId.ToLower() : inherenceData.Issuer.ToHexString().ToLower(); string commitmentToRoot = inherenceData.AssetRootCommitment.ToHexString(); if (!ConfidentialAssetsHelper.VerifySurjectionProof(inherenceData.RootRegistrationProof, inherenceData.AssetRootCommitment)) { _logger.Error($"[{_inherenceService.AccountId}]: Registration Proofs failed for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); throw new InherenceRegistrationProofsIncorrectException(); } if (inherenceData.AssociatedRootCommitment != null) { //============================================================================= // In the case when AssociatedRootCommitment is not null one of the following scenarios can occur: // 1. The user already has Root Inherence Protection attribute - in this case // image provided for registration must be checked for compliance with the existing factor // 2. The user does not have yet Root Protection attribute - in this case user must provide two images, // one for the Root Inherence protection attribute and the second for associated one. // Both images must be checked for matching and then two attributes will be created. //============================================================================= _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(InherenceData)} with {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} contains {nameof(inherenceData.AssociatedRootCommitment)}"); byte[] commitment = ConfidentialAssetsHelper.SumCommitments(inherenceData.AssetRootCommitment, inherenceData.AssociatedRootCommitment); if (!ConfidentialAssetsHelper.VerifySurjectionProof(inherenceData.AssociatedRegistrationProof, commitment)) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(inherenceData.AssociatedRegistrationProof)} failed for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); return(BadRequest(Resources.ERR_INHERENCE_REGISTRATION_PROOFS_INCORRECT)); } string commitmentToAssociated = inherenceData.AssociatedRootCommitment.ToHexString(); string associatedRegistrationKey = inherenceData.AssociatedRegistrationProof.AssetCommitments[0].ToHexString(); _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, associated commitment is {commitmentToAssociated} and registration key is {associatedRegistrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} obtained"); if (!biometricPersonData.Images.ContainsKey(commitmentToAssociated)) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, no image found for the associated commitment {commitmentToAssociated}"); return(BadRequest($"No image found for the associated commitment {commitmentToAssociated}")); } Guid rootRegistrationGuid = await GetPersonRegistrationGuid(personGroupId, registrationKey).ConfigureAwait(false); if (Guid.Empty.Equals(rootRegistrationGuid)) { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, No root registration found for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); if (!biometricPersonData.Images.ContainsKey(commitmentToRoot)) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, no image found for the root commitment {commitmentToRoot}"); return(BadRequest($"No image found for the root commitment {commitmentToRoot}")); } imageContent = biometricPersonData.Images[commitmentToRoot]; byte[] faceAssociated = biometricPersonData.Images[commitmentToAssociated]; bool matches = await _facesService.VerifyFaces(imageContent, faceAssociated).ConfigureAwait(false); if (!matches) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, faces do not match for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); return(BadRequest("Provided face images do not match one to another")); } PersonFaceData rootFaceData = new PersonFaceData { PersonGroupId = personGroupId, Name = registrationKey, UserData = registrationKey, ImageContent = imageContent }; _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, adding root registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); await AddPerson(rootFaceData).ConfigureAwait(false); registrationKey = inherenceData.AssociatedRegistrationProof.AssetCommitments[0].ToHexString(); imageContent = faceAssociated; _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, proceeding with associated registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); } else { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, Root registration with key {registrationKey} found for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); registrationKey = inherenceData.AssociatedRegistrationProof.AssetCommitments[0].ToHexString(); imageContent = biometricPersonData.Images.ContainsKey(commitmentToAssociated) ? biometricPersonData.Images[commitmentToAssociated] : null; bool isIdentical = await VerifyPersonFace(personGroupId, rootRegistrationGuid, imageContent).ConfigureAwait(false); if (!isIdentical) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, face do not match to registered one for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); throw new InherenceCrossMatchingFailedException(inherenceData.RootRegistrationProof.AssetCommitments[0].ToHexString()); } _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, proceeding with associated registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); } } else { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, {nameof(InherenceData)} with {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey} does not contain {nameof(inherenceData.AssociatedRootCommitment)}"); if (!biometricPersonData.Images.ContainsKey(commitmentToRoot)) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, no image found for the root commitment {commitmentToRoot}"); return(BadRequest($"No image found for the root commitment {commitmentToRoot}")); } imageContent = biometricPersonData.Images[commitmentToRoot]; } Guid guid = _dataAccessService.FindPersonGuid(registrationKey); PersonFaceData personFaceData = new PersonFaceData { PersonGroupId = personGroupId, Name = registrationKey, UserData = registrationKey, ImageContent = imageContent }; try { if (guid == Guid.Empty) { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, adding registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); await AddPerson(personFaceData).ConfigureAwait(false); } else { _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, replacing registration {registrationKey} for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); await ReplacePerson(personFaceData).ConfigureAwait(false); } } catch (Exception ex) { if (ex is AggregateException aex) { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)} failed with aggregated exception", aex.InnerException); } else { _logger.Error($"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)} failed with exception", ex); } throw; } _logger.LogIfDebug(() => $"[{_inherenceService.AccountId}]: {nameof(RegisterPerson)}, completed successfully for {nameof(biometricPersonData.SessionKey)}={biometricPersonData.SessionKey}"); return(Ok()); }