Enumerable with value semantic
ADD
WalletWasabi/Extensions/ImmutableValueSequenceExtensions.cs
+using System;
+using System.Collections.Generic;
+using WalletWasabi.Models;
+
+namespace WalletWasabi.Extensions
+{
+ internal static class ImmutableValueSequenceExtensions
+ {
+ public static ImmutableValueSequence<T> ToImmutableValueSequence<T>(this IEnumerable<T> list) where T : IEquatable<T>
+ => new(list);
+ }
+}

ADD
WalletWasabi/Models/ImmutableValueSequence.cs
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace WalletWasabi.Models
+{
+ /// <summary>
+ /// ImmutableValueSequence represents an immutable sequence with value semantics, meaning that
+ /// it can be compared with other sequences and the equality of two sequences is based on the
+ /// equality of the elements.
+ /// </summary>
+ public class ImmutableValueSequence<T> : IEnumerable<T>, IEquatable<IEnumerable<T>> where T : IEquatable<T>
+ {
+ private readonly ImmutableArray<T> _elements;
+
+ public ImmutableValueSequence(IEnumerable<T> sequence)
+ {
+ _elements = sequence.ToImmutableArray();
+ }
+
+ public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>)_elements).GetEnumerator();
+
+ public override int GetHashCode()
+ {
+ var hash = new HashCode();
+ foreach (var element in _elements)
+ {
+ hash.Add(element);
+ }
+ return hash.ToHashCode();
+ }
+
+ public bool Equals(IEnumerable<T>? other)
+ => this.SequenceEqual(other ?? Enumerable.Empty<T>());
+
+ public override bool Equals(object? obj) => Equals(obj as IEnumerable<T>);
+
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_elements).GetEnumerator();
+ }
+}

MODIFY
WalletWasabi/WabiSabi/Crypto/CredentialRequesting/CredentialsRequest.cs
WalletWasabi/WabiSabi/Crypto/CredentialRequesting/CredentialsRequest.cs
using Newtonsoft.Json;
-using System;
using System.Collections.Generic;
using System.Linq;
-using WalletWasabi.Crypto;
using WalletWasabi.Crypto.Groups;
using WalletWasabi.Crypto.ZeroKnowledge;
+using WalletWasabi.Extensions;
+using WalletWasabi.Models;
namespace WalletWasabi.WabiSabi.Crypto.CredentialRequesting
{
@@ -16,7 +16,7 @@ namespace WalletWasabi.WabiSabi.Crypto.CredentialRequesting
/// inputs registration and outputs registration and it is designed to support
/// credentials reissuance.
/// </remarks>
- public abstract class CredentialsRequest : IEquatable<CredentialsRequest>
+ public abstract record CredentialsRequest
{
[JsonConstructor]
internal CredentialsRequest(
@@ -26,9 +26,9 @@ namespace WalletWasabi.WabiSabi.Crypto.CredentialRequesting
IEnumerable<Proof> proofs)
{
Delta = delta;
- Presented = presented;
- Requested = requested;
- Proofs = proofs;
+ Presented = presented.ToImmutableValueSequence();
+ Requested = requested.ToImmutableValueSequence();
+ Proofs = proofs.ToImmutableValueSequence();
}
/// <summary>
@@ -44,17 +44,17 @@ namespace WalletWasabi.WabiSabi.Crypto.CredentialRequesting
/// <summary>
/// Randomized credentials presented for output registration or reissuance.
/// </summary>
- public IEnumerable<CredentialPresentation> Presented { get; }
+ public ImmutableValueSequence<CredentialPresentation> Presented { get; }
/// <summary>
/// Credential isssuance requests.
/// </summary>
- public IEnumerable<IssuanceRequest> Requested { get; }
+ public ImmutableValueSequence<IssuanceRequest> Requested { get; }
/// <summary>
/// Accompanying range and sum proofs to the coordinator.
/// </summary>
- public IEnumerable<Proof> Proofs { get; }
+ public ImmutableValueSequence<Proof> Proofs { get; }
/// <summary>
/// Is request for zero-value credentials only.
@@ -79,51 +79,5 @@ namespace WalletWasabi.WabiSabi.Crypto.CredentialRequesting
/// </summary>
[JsonIgnore]
internal bool AreThereDuplicatedSerialNumbers => SerialNumbers.Distinct().Count() < SerialNumbers.Count();
-
- public override int GetHashCode()
- {
- int hc = 0;
-
- foreach (var element in Presented)
- {
- hc ^= element.GetHashCode();
- hc = (hc << 7) | (hc >> (32 - 7));
- }
-
- foreach (var element in Requested)
- {
- hc ^= element.GetHashCode();
- hc = (hc << 7) | (hc >> (32 - 7));
- }
-
- foreach (var element in Proofs)
- {
- hc ^= element.GetHashCode();
- hc = (hc << 7) | (hc >> (32 - 7));
- }
-
- return HashCode.Combine(Delta.GetHashCode(), hc);
- }
-
- public static bool operator ==(CredentialsRequest? x, CredentialsRequest? y) => x?.Equals(y) ?? false;
-
- public static bool operator !=(CredentialsRequest? x, CredentialsRequest? y) => !(x == y);
-
- public override bool Equals(object? other) => Equals(other as CredentialsRequest);
-
- public bool Equals(CredentialsRequest? other)
- {
- if (other is null)
- {
- return false;
- }
-
- bool isEqual = Delta == other.Delta
- && Presented.SequenceEqual(other.Presented)
- && Requested.SequenceEqual(other.Requested)
- && Proofs.SequenceEqual(other.Proofs);
-
- return isEqual;
- }
}
}

MODIFY
WalletWasabi/WabiSabi/Crypto/CredentialRequesting/RealCredentialsRequest.cs
WalletWasabi/WabiSabi/Crypto/CredentialRequesting/RealCredentialsRequest.cs
-using NBitcoin;
-using NBitcoin.Secp256k1;
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using WalletWasabi.Crypto.ZeroKnowledge;
namespace WalletWasabi.WabiSabi.Crypto.CredentialRequesting
{
- public class RealCredentialsRequest : CredentialsRequest
+ public record RealCredentialsRequest : CredentialsRequest
{
public RealCredentialsRequest(
long delta,

MODIFY
WalletWasabi/WabiSabi/Crypto/CredentialRequesting/ZeroCredentialsRequest.cs
WalletWasabi/WabiSabi/Crypto/CredentialRequesting/ZeroCredentialsRequest.cs
-using NBitcoin;
-using NBitcoin.Secp256k1;
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using WalletWasabi.Crypto.ZeroKnowledge;
namespace WalletWasabi.WabiSabi.Crypto.CredentialRequesting
{
- public class ZeroCredentialsRequest : CredentialsRequest
+ public record ZeroCredentialsRequest : CredentialsRequest
{
public ZeroCredentialsRequest(
IEnumerable<IssuanceRequest> requested,

Enumerable with value semantic