diff --git a/backend/mpc-system/.claude/settings.local.json b/backend/mpc-system/.claude/settings.local.json
index 908df022..55c7ca49 100644
--- a/backend/mpc-system/.claude/settings.local.json
+++ b/backend/mpc-system/.claude/settings.local.json
@@ -19,7 +19,11 @@
"Bash(Select-String -Pattern \"grpc_handler.go\")",
"Bash(Select-Object -First 10)",
"Bash(git add:*)",
- "Bash(git commit:*)"
+ "Bash(git commit:*)",
+ "Bash(where:*)",
+ "Bash(go get:*)",
+ "Bash(findstr:*)",
+ "Bash(git push)"
],
"deny": [],
"ask": []
diff --git a/backend/mpc-system/coverage.html b/backend/mpc-system/coverage.html
deleted file mode 100644
index cc59b7dc..00000000
--- a/backend/mpc-system/coverage.html
+++ /dev/null
@@ -1,2467 +0,0 @@
-
-
-
-
-
-
-
package crypto
-
-import (
- "crypto/aes"
- "crypto/cipher"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/sha256"
- "encoding/hex"
- "errors"
- "io"
- "math/big"
-
- "golang.org/x/crypto/hkdf"
-)
-
-var (
- ErrInvalidKeySize = errors.New("invalid key size")
- ErrInvalidCipherText = errors.New("invalid ciphertext")
- ErrEncryptionFailed = errors.New("encryption failed")
- ErrDecryptionFailed = errors.New("decryption failed")
- ErrInvalidPublicKey = errors.New("invalid public key")
- ErrInvalidSignature = errors.New("invalid signature")
-)
-
-// CryptoService provides cryptographic operations
-type CryptoService struct {
- masterKey []byte
-}
-
-// NewCryptoService creates a new crypto service
-func NewCryptoService(masterKey []byte) (*CryptoService, error) {
- if len(masterKey) != 32 {
- return nil, ErrInvalidKeySize
- }
- return &CryptoService{masterKey: masterKey}, nil
-}
-
-// GenerateRandomBytes generates random bytes
-func GenerateRandomBytes(n int) ([]byte, error) {
- b := make([]byte, n)
- _, err := rand.Read(b)
- if err != nil {
- return nil, err
- }
- return b, nil
-}
-
-// GenerateRandomHex generates a random hex string
-func GenerateRandomHex(n int) (string, error) {
- bytes, err := GenerateRandomBytes(n)
- if err != nil {
- return "", err
- }
- return hex.EncodeToString(bytes), nil
-}
-
-// DeriveKey derives a key from the master key using HKDF
-func (c *CryptoService) DeriveKey(context string, length int) ([]byte, error) {
- hkdfReader := hkdf.New(sha256.New, c.masterKey, nil, []byte(context))
- key := make([]byte, length)
- if _, err := io.ReadFull(hkdfReader, key); err != nil {
- return nil, err
- }
- return key, nil
-}
-
-// EncryptShare encrypts a key share using AES-256-GCM
-func (c *CryptoService) EncryptShare(shareData []byte, partyID string) ([]byte, error) {
- // Derive a unique key for this party
- key, err := c.DeriveKey("share_encryption:"+partyID, 32)
- if err != nil {
- return nil, err
- }
-
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
-
- aesGCM, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
-
- nonce := make([]byte, aesGCM.NonceSize())
- if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
- return nil, err
- }
-
- // Encrypt and prepend nonce
- ciphertext := aesGCM.Seal(nonce, nonce, shareData, []byte(partyID))
- return ciphertext, nil
-}
-
-// DecryptShare decrypts a key share
-func (c *CryptoService) DecryptShare(encryptedData []byte, partyID string) ([]byte, error) {
- // Derive the same key used for encryption
- key, err := c.DeriveKey("share_encryption:"+partyID, 32)
- if err != nil {
- return nil, err
- }
-
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
-
- aesGCM, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
-
- nonceSize := aesGCM.NonceSize()
- if len(encryptedData) < nonceSize {
- return nil, ErrInvalidCipherText
- }
-
- nonce, ciphertext := encryptedData[:nonceSize], encryptedData[nonceSize:]
- plaintext, err := aesGCM.Open(nil, nonce, ciphertext, []byte(partyID))
- if err != nil {
- return nil, ErrDecryptionFailed
- }
-
- return plaintext, nil
-}
-
-// EncryptMessage encrypts a message using AES-256-GCM
-func (c *CryptoService) EncryptMessage(plaintext []byte) ([]byte, error) {
- block, err := aes.NewCipher(c.masterKey)
- if err != nil {
- return nil, err
- }
-
- aesGCM, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
-
- nonce := make([]byte, aesGCM.NonceSize())
- if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
- return nil, err
- }
-
- ciphertext := aesGCM.Seal(nonce, nonce, plaintext, nil)
- return ciphertext, nil
-}
-
-// DecryptMessage decrypts a message
-func (c *CryptoService) DecryptMessage(ciphertext []byte) ([]byte, error) {
- block, err := aes.NewCipher(c.masterKey)
- if err != nil {
- return nil, err
- }
-
- aesGCM, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
-
- nonceSize := aesGCM.NonceSize()
- if len(ciphertext) < nonceSize {
- return nil, ErrInvalidCipherText
- }
-
- nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
- plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil)
- if err != nil {
- return nil, ErrDecryptionFailed
- }
-
- return plaintext, nil
-}
-
-// Hash256 computes SHA-256 hash
-func Hash256(data []byte) []byte {
- hash := sha256.Sum256(data)
- return hash[:]
-}
-
-// VerifyECDSASignature verifies an ECDSA signature
-func VerifyECDSASignature(messageHash, signature, publicKey []byte) (bool, error) {
- // Parse public key (assuming secp256k1/P256 uncompressed format)
- curve := elliptic.P256()
- x, y := elliptic.Unmarshal(curve, publicKey)
- if x == nil {
- return false, ErrInvalidPublicKey
- }
-
- pubKey := &ecdsa.PublicKey{
- Curve: curve,
- X: x,
- Y: y,
- }
-
- // Parse signature (R || S, each 32 bytes)
- if len(signature) != 64 {
- return false, ErrInvalidSignature
- }
-
- r := new(big.Int).SetBytes(signature[:32])
- s := new(big.Int).SetBytes(signature[32:])
-
- // Verify signature
- valid := ecdsa.Verify(pubKey, messageHash, r, s)
- return valid, nil
-}
-
-// GenerateNonce generates a cryptographic nonce
-func GenerateNonce() ([]byte, error) {
- return GenerateRandomBytes(32)
-}
-
-// SecureCompare performs constant-time comparison
-func SecureCompare(a, b []byte) bool {
- if len(a) != len(b) {
- return false
- }
-
- var result byte
- for i := 0; i < len(a); i++ {
- result |= a[i] ^ b[i]
- }
- return result == 0
-}
-
-// ParsePublicKey parses a public key from bytes (P256 uncompressed format)
-func ParsePublicKey(publicKeyBytes []byte) (*ecdsa.PublicKey, error) {
- curve := elliptic.P256()
- x, y := elliptic.Unmarshal(curve, publicKeyBytes)
- if x == nil {
- return nil, ErrInvalidPublicKey
- }
-
- return &ecdsa.PublicKey{
- Curve: curve,
- X: x,
- Y: y,
- }, nil
-}
-
-// VerifySignature verifies an ECDSA signature using a public key
-func VerifySignature(pubKey *ecdsa.PublicKey, messageHash, signature []byte) bool {
- // Parse signature (R || S, each 32 bytes)
- if len(signature) != 64 {
- return false
- }
-
- r := new(big.Int).SetBytes(signature[:32])
- s := new(big.Int).SetBytes(signature[32:])
-
- return ecdsa.Verify(pubKey, messageHash, r, s)
-}
-
-// HashMessage computes SHA-256 hash of a message (alias for Hash256)
-func HashMessage(message []byte) []byte {
- return Hash256(message)
-}
-
-// Encrypt encrypts data using AES-256-GCM with the provided key
-func Encrypt(key, plaintext []byte) ([]byte, error) {
- if len(key) != 32 {
- return nil, ErrInvalidKeySize
- }
-
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
-
- aesGCM, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
-
- nonce := make([]byte, aesGCM.NonceSize())
- if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
- return nil, err
- }
-
- ciphertext := aesGCM.Seal(nonce, nonce, plaintext, nil)
- return ciphertext, nil
-}
-
-// Decrypt decrypts data using AES-256-GCM with the provided key
-func Decrypt(key, ciphertext []byte) ([]byte, error) {
- if len(key) != 32 {
- return nil, ErrInvalidKeySize
- }
-
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
-
- aesGCM, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
-
- nonceSize := aesGCM.NonceSize()
- if len(ciphertext) < nonceSize {
- return nil, ErrInvalidCipherText
- }
-
- nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
- plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil)
- if err != nil {
- return nil, ErrDecryptionFailed
- }
-
- return plaintext, nil
-}
-
-// DeriveKey derives a key from secret and salt using HKDF (standalone function)
-func DeriveKey(secret, salt []byte, length int) ([]byte, error) {
- hkdfReader := hkdf.New(sha256.New, secret, salt, nil)
- key := make([]byte, length)
- if _, err := io.ReadFull(hkdfReader, key); err != nil {
- return nil, err
- }
- return key, nil
-}
-
-// SignMessage signs a message using ECDSA private key
-func SignMessage(privateKey *ecdsa.PrivateKey, message []byte) ([]byte, error) {
- hash := Hash256(message)
- r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash)
- if err != nil {
- return nil, err
- }
-
- // Encode R and S as 32 bytes each (total 64 bytes)
- signature := make([]byte, 64)
- rBytes := r.Bytes()
- sBytes := s.Bytes()
-
- // Pad with zeros if necessary
- copy(signature[32-len(rBytes):32], rBytes)
- copy(signature[64-len(sBytes):64], sBytes)
-
- return signature, nil
-}
-
-// EncodeToHex encodes bytes to hex string
-func EncodeToHex(data []byte) string {
- return hex.EncodeToString(data)
-}
-
-// DecodeFromHex decodes hex string to bytes
-func DecodeFromHex(s string) ([]byte, error) {
- return hex.DecodeString(s)
-}
-
-// EncodeToBase64 encodes bytes to base64 string
-func EncodeToBase64(data []byte) string {
- return hex.EncodeToString(data) // Using hex for simplicity, could use base64
-}
-
-// DecodeFromBase64 decodes base64 string to bytes
-func DecodeFromBase64(s string) ([]byte, error) {
- return hex.DecodeString(s)
-}
-
-// MarshalPublicKey marshals an ECDSA public key to bytes
-func MarshalPublicKey(pubKey *ecdsa.PublicKey) []byte {
- return elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y)
-}
-
-// CompareBytes performs constant-time comparison of two byte slices
-func CompareBytes(a, b []byte) bool {
- return SecureCompare(a, b)
-}
-
-
-
package jwt
-
-import (
- "errors"
- "time"
-
- "github.com/golang-jwt/jwt/v5"
- "github.com/google/uuid"
-)
-
-var (
- ErrInvalidToken = errors.New("invalid token")
- ErrExpiredToken = errors.New("token expired")
- ErrInvalidClaims = errors.New("invalid claims")
- ErrTokenNotYetValid = errors.New("token not yet valid")
-)
-
-// Claims represents custom JWT claims
-type Claims struct {
- SessionID string `json:"session_id"`
- PartyID string `json:"party_id"`
- TokenType string `json:"token_type"` // "join", "access", "refresh"
- jwt.RegisteredClaims
-}
-
-// JWTService provides JWT operations
-type JWTService struct {
- secretKey []byte
- issuer string
- tokenExpiry time.Duration
- refreshExpiry time.Duration
-}
-
-// NewJWTService creates a new JWT service
-func NewJWTService(secretKey string, issuer string, tokenExpiry, refreshExpiry time.Duration) *JWTService {
- return &JWTService{
- secretKey: []byte(secretKey),
- issuer: issuer,
- tokenExpiry: tokenExpiry,
- refreshExpiry: refreshExpiry,
- }
-}
-
-// GenerateJoinToken generates a token for joining an MPC session
-func (s *JWTService) GenerateJoinToken(sessionID uuid.UUID, partyID string, expiresIn time.Duration) (string, error) {
- now := time.Now()
- claims := Claims{
- SessionID: sessionID.String(),
- PartyID: partyID,
- TokenType: "join",
- RegisteredClaims: jwt.RegisteredClaims{
- ID: uuid.New().String(),
- Issuer: s.issuer,
- Subject: partyID,
- IssuedAt: jwt.NewNumericDate(now),
- NotBefore: jwt.NewNumericDate(now),
- ExpiresAt: jwt.NewNumericDate(now.Add(expiresIn)),
- },
- }
-
- token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
- return token.SignedString(s.secretKey)
-}
-
-// AccessTokenClaims represents claims in an access token
-type AccessTokenClaims struct {
- Subject string
- Username string
- Issuer string
-}
-
-// GenerateAccessToken generates an access token with username
-func (s *JWTService) GenerateAccessToken(userID, username string) (string, error) {
- now := time.Now()
- claims := Claims{
- TokenType: "access",
- RegisteredClaims: jwt.RegisteredClaims{
- ID: uuid.New().String(),
- Issuer: s.issuer,
- Subject: userID,
- IssuedAt: jwt.NewNumericDate(now),
- NotBefore: jwt.NewNumericDate(now),
- ExpiresAt: jwt.NewNumericDate(now.Add(s.tokenExpiry)),
- },
- }
- // Store username in PartyID field for access tokens
- claims.PartyID = username
-
- token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
- return token.SignedString(s.secretKey)
-}
-
-// GenerateRefreshToken generates a refresh token
-func (s *JWTService) GenerateRefreshToken(userID string) (string, error) {
- now := time.Now()
- claims := Claims{
- TokenType: "refresh",
- RegisteredClaims: jwt.RegisteredClaims{
- ID: uuid.New().String(),
- Issuer: s.issuer,
- Subject: userID,
- IssuedAt: jwt.NewNumericDate(now),
- NotBefore: jwt.NewNumericDate(now),
- ExpiresAt: jwt.NewNumericDate(now.Add(s.refreshExpiry)),
- },
- }
-
- token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
- return token.SignedString(s.secretKey)
-}
-
-// ValidateToken validates a JWT token and returns the claims
-func (s *JWTService) ValidateToken(tokenString string) (*Claims, error) {
- token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
- if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
- return nil, ErrInvalidToken
- }
- return s.secretKey, nil
- })
-
- if err != nil {
- if errors.Is(err, jwt.ErrTokenExpired) {
- return nil, ErrExpiredToken
- }
- return nil, ErrInvalidToken
- }
-
- claims, ok := token.Claims.(*Claims)
- if !ok || !token.Valid {
- return nil, ErrInvalidClaims
- }
-
- return claims, nil
-}
-
-// ValidateJoinToken validates a join token for MPC sessions
-func (s *JWTService) ValidateJoinToken(tokenString string, sessionID uuid.UUID, partyID string) (*Claims, error) {
- claims, err := s.ValidateToken(tokenString)
- if err != nil {
- return nil, err
- }
-
- if claims.TokenType != "join" {
- return nil, ErrInvalidToken
- }
-
- if claims.SessionID != sessionID.String() {
- return nil, ErrInvalidClaims
- }
-
- if claims.PartyID != partyID {
- return nil, ErrInvalidClaims
- }
-
- return claims, nil
-}
-
-// RefreshAccessToken creates a new access token from a valid refresh token
-func (s *JWTService) RefreshAccessToken(refreshToken string) (string, error) {
- claims, err := s.ValidateToken(refreshToken)
- if err != nil {
- return "", err
- }
-
- if claims.TokenType != "refresh" {
- return "", ErrInvalidToken
- }
-
- // PartyID stores the username for access tokens
- return s.GenerateAccessToken(claims.Subject, claims.PartyID)
-}
-
-// ValidateAccessToken validates an access token and returns structured claims
-func (s *JWTService) ValidateAccessToken(tokenString string) (*AccessTokenClaims, error) {
- claims, err := s.ValidateToken(tokenString)
- if err != nil {
- return nil, err
- }
-
- if claims.TokenType != "access" {
- return nil, ErrInvalidToken
- }
-
- return &AccessTokenClaims{
- Subject: claims.Subject,
- Username: claims.PartyID, // Username stored in PartyID for access tokens
- Issuer: claims.Issuer,
- }, nil
-}
-
-// ValidateRefreshToken validates a refresh token and returns claims
-func (s *JWTService) ValidateRefreshToken(tokenString string) (*Claims, error) {
- claims, err := s.ValidateToken(tokenString)
- if err != nil {
- return nil, err
- }
-
- if claims.TokenType != "refresh" {
- return nil, ErrInvalidToken
- }
-
- return claims, nil
-}
-
-// TokenGenerator interface for dependency injection
-type TokenGenerator interface {
- GenerateJoinToken(sessionID uuid.UUID, partyID string, expiresIn time.Duration) (string, error)
-}
-
-// TokenValidator interface for dependency injection
-type TokenValidator interface {
- ValidateJoinToken(tokenString string, sessionID uuid.UUID, partyID string) (*Claims, error)
-}
-
-// Ensure JWTService implements interfaces
-var _ TokenGenerator = (*JWTService)(nil)
-var _ TokenValidator = (*JWTService)(nil)
-
-
-
package utils
-
-import (
- "context"
- "encoding/json"
- "math/big"
- "reflect"
- "strings"
- "time"
-
- "github.com/google/uuid"
-)
-
-// GenerateID generates a new UUID
-func GenerateID() uuid.UUID {
- return uuid.New()
-}
-
-// ParseUUID parses a string to UUID
-func ParseUUID(s string) (uuid.UUID, error) {
- return uuid.Parse(s)
-}
-
-// MustParseUUID parses a string to UUID, panics on error
-func MustParseUUID(s string) uuid.UUID {
- id, err := uuid.Parse(s)
- if err != nil {
- panic(err)
- }
- return id
-}
-
-// IsValidUUID checks if a string is a valid UUID
-func IsValidUUID(s string) bool {
- _, err := uuid.Parse(s)
- return err == nil
-}
-
-// ToJSON converts an interface to JSON bytes
-func ToJSON(v interface{}) ([]byte, error) {
- return json.Marshal(v)
-}
-
-// FromJSON converts JSON bytes to an interface
-func FromJSON(data []byte, v interface{}) error {
- return json.Unmarshal(data, v)
-}
-
-// NowUTC returns the current UTC time
-func NowUTC() time.Time {
- return time.Now().UTC()
-}
-
-// TimePtr returns a pointer to the time
-func TimePtr(t time.Time) *time.Time {
- return &t
-}
-
-// NowPtr returns a pointer to the current time
-func NowPtr() *time.Time {
- now := NowUTC()
- return &now
-}
-
-// BigIntToBytes converts a big.Int to bytes (32 bytes, left-padded)
-func BigIntToBytes(n *big.Int) []byte {
- if n == nil {
- return make([]byte, 32)
- }
- b := n.Bytes()
- if len(b) > 32 {
- return b[:32]
- }
- if len(b) < 32 {
- result := make([]byte, 32)
- copy(result[32-len(b):], b)
- return result
- }
- return b
-}
-
-// BytesToBigInt converts bytes to big.Int
-func BytesToBigInt(b []byte) *big.Int {
- return new(big.Int).SetBytes(b)
-}
-
-// StringSliceContains checks if a string slice contains a value
-func StringSliceContains(slice []string, value string) bool {
- for _, s := range slice {
- if s == value {
- return true
- }
- }
- return false
-}
-
-// StringSliceRemove removes a value from a string slice
-func StringSliceRemove(slice []string, value string) []string {
- result := make([]string, 0, len(slice))
- for _, s := range slice {
- if s != value {
- result = append(result, s)
- }
- }
- return result
-}
-
-// UniqueStrings returns unique strings from a slice
-func UniqueStrings(slice []string) []string {
- seen := make(map[string]struct{})
- result := make([]string, 0, len(slice))
- for _, s := range slice {
- if _, ok := seen[s]; !ok {
- seen[s] = struct{}{}
- result = append(result, s)
- }
- }
- return result
-}
-
-// TruncateString truncates a string to max length
-func TruncateString(s string, maxLen int) string {
- if len(s) <= maxLen {
- return s
- }
- return s[:maxLen]
-}
-
-// SafeString returns an empty string if the pointer is nil
-func SafeString(s *string) string {
- if s == nil {
- return ""
- }
- return *s
-}
-
-// StringPtr returns a pointer to the string
-func StringPtr(s string) *string {
- return &s
-}
-
-// IntPtr returns a pointer to the int
-func IntPtr(i int) *int {
- return &i
-}
-
-// BoolPtr returns a pointer to the bool
-func BoolPtr(b bool) *bool {
- return &b
-}
-
-// IsZero checks if a value is zero/empty
-func IsZero(v interface{}) bool {
- return reflect.ValueOf(v).IsZero()
-}
-
-// Coalesce returns the first non-zero value
-func Coalesce[T comparable](values ...T) T {
- var zero T
- for _, v := range values {
- if v != zero {
- return v
- }
- }
- return zero
-}
-
-// MapKeys returns the keys of a map
-func MapKeys[K comparable, V any](m map[K]V) []K {
- keys := make([]K, 0, len(m))
- for k := range m {
- keys = append(keys, k)
- }
- return keys
-}
-
-// MapValues returns the values of a map
-func MapValues[K comparable, V any](m map[K]V) []V {
- values := make([]V, 0, len(m))
- for _, v := range m {
- values = append(values, v)
- }
- return values
-}
-
-// Min returns the minimum of two values
-func Min[T ~int | ~int64 | ~float64](a, b T) T {
- if a < b {
- return a
- }
- return b
-}
-
-// Max returns the maximum of two values
-func Max[T ~int | ~int64 | ~float64](a, b T) T {
- if a > b {
- return a
- }
- return b
-}
-
-// Clamp clamps a value between min and max
-func Clamp[T ~int | ~int64 | ~float64](value, min, max T) T {
- if value < min {
- return min
- }
- if value > max {
- return max
- }
- return value
-}
-
-// ContextWithTimeout creates a context with timeout
-func ContextWithTimeout(timeout time.Duration) (context.Context, context.CancelFunc) {
- return context.WithTimeout(context.Background(), timeout)
-}
-
-// MaskString masks a string showing only first and last n characters
-func MaskString(s string, showChars int) string {
- if len(s) <= showChars*2 {
- return strings.Repeat("*", len(s))
- }
- return s[:showChars] + strings.Repeat("*", len(s)-showChars*2) + s[len(s)-showChars:]
-}
-
-// Retry executes a function with retries
-func Retry(attempts int, sleep time.Duration, f func() error) error {
- var err error
- for i := 0; i < attempts; i++ {
- if err = f(); err == nil {
- return nil
- }
- if i < attempts-1 {
- time.Sleep(sleep)
- sleep *= 2 // Exponential backoff
- }
- }
- return err
-}
-
-
-
package entities
-
-import (
- "time"
-
- "github.com/google/uuid"
- "github.com/rwadurian/mpc-system/services/account/domain/value_objects"
-)
-
-// Account represents a user account with MPC-based authentication
-type Account struct {
- ID value_objects.AccountID
- Username string
- Email string
- Phone *string
- PublicKey []byte // MPC group public key
- KeygenSessionID uuid.UUID
- ThresholdN int
- ThresholdT int
- Status value_objects.AccountStatus
- CreatedAt time.Time
- UpdatedAt time.Time
- LastLoginAt *time.Time
-}
-
-// NewAccount creates a new Account
-func NewAccount(
- username string,
- email string,
- publicKey []byte,
- keygenSessionID uuid.UUID,
- thresholdN int,
- thresholdT int,
-) *Account {
- now := time.Now().UTC()
- return &Account{
- ID: value_objects.NewAccountID(),
- Username: username,
- Email: email,
- PublicKey: publicKey,
- KeygenSessionID: keygenSessionID,
- ThresholdN: thresholdN,
- ThresholdT: thresholdT,
- Status: value_objects.AccountStatusActive,
- CreatedAt: now,
- UpdatedAt: now,
- }
-}
-
-// SetPhone sets the phone number
-func (a *Account) SetPhone(phone string) {
- a.Phone = &phone
- a.UpdatedAt = time.Now().UTC()
-}
-
-// UpdateLastLogin updates the last login timestamp
-func (a *Account) UpdateLastLogin() {
- now := time.Now().UTC()
- a.LastLoginAt = &now
- a.UpdatedAt = now
-}
-
-// Suspend suspends the account
-func (a *Account) Suspend() error {
- if a.Status == value_objects.AccountStatusRecovering {
- return ErrAccountInRecovery
- }
- a.Status = value_objects.AccountStatusSuspended
- a.UpdatedAt = time.Now().UTC()
- return nil
-}
-
-// Lock locks the account
-func (a *Account) Lock() error {
- if a.Status == value_objects.AccountStatusRecovering {
- return ErrAccountInRecovery
- }
- a.Status = value_objects.AccountStatusLocked
- a.UpdatedAt = time.Now().UTC()
- return nil
-}
-
-// Activate activates the account
-func (a *Account) Activate() {
- a.Status = value_objects.AccountStatusActive
- a.UpdatedAt = time.Now().UTC()
-}
-
-// StartRecovery marks the account as recovering
-func (a *Account) StartRecovery() error {
- if !a.Status.CanInitiateRecovery() {
- return ErrCannotInitiateRecovery
- }
- a.Status = value_objects.AccountStatusRecovering
- a.UpdatedAt = time.Now().UTC()
- return nil
-}
-
-// CompleteRecovery completes the recovery process with new public key
-func (a *Account) CompleteRecovery(newPublicKey []byte, newKeygenSessionID uuid.UUID) {
- a.PublicKey = newPublicKey
- a.KeygenSessionID = newKeygenSessionID
- a.Status = value_objects.AccountStatusActive
- a.UpdatedAt = time.Now().UTC()
-}
-
-// CanLogin checks if the account can login
-func (a *Account) CanLogin() bool {
- return a.Status.CanLogin()
-}
-
-// IsActive checks if the account is active
-func (a *Account) IsActive() bool {
- return a.Status == value_objects.AccountStatusActive
-}
-
-// Validate validates the account data
-func (a *Account) Validate() error {
- if a.Username == "" {
- return ErrInvalidUsername
- }
- if a.Email == "" {
- return ErrInvalidEmail
- }
- if len(a.PublicKey) == 0 {
- return ErrInvalidPublicKey
- }
- if a.ThresholdT > a.ThresholdN || a.ThresholdT <= 0 {
- return ErrInvalidThreshold
- }
- return nil
-}
-
-// Account errors
-var (
- ErrInvalidUsername = &AccountError{Code: "INVALID_USERNAME", Message: "username is required"}
- ErrInvalidEmail = &AccountError{Code: "INVALID_EMAIL", Message: "email is required"}
- ErrInvalidPublicKey = &AccountError{Code: "INVALID_PUBLIC_KEY", Message: "public key is required"}
- ErrInvalidThreshold = &AccountError{Code: "INVALID_THRESHOLD", Message: "invalid threshold configuration"}
- ErrAccountInRecovery = &AccountError{Code: "ACCOUNT_IN_RECOVERY", Message: "account is in recovery mode"}
- ErrCannotInitiateRecovery = &AccountError{Code: "CANNOT_INITIATE_RECOVERY", Message: "cannot initiate recovery in current state"}
- ErrAccountNotActive = &AccountError{Code: "ACCOUNT_NOT_ACTIVE", Message: "account is not active"}
- ErrAccountNotFound = &AccountError{Code: "ACCOUNT_NOT_FOUND", Message: "account not found"}
- ErrDuplicateUsername = &AccountError{Code: "DUPLICATE_USERNAME", Message: "username already exists"}
- ErrDuplicateEmail = &AccountError{Code: "DUPLICATE_EMAIL", Message: "email already exists"}
-)
-
-// AccountError represents an account domain error
-type AccountError struct {
- Code string
- Message string
-}
-
-func (e *AccountError) Error() string {
- return e.Message
-}
-
-
-
package entities
-
-import (
- "time"
-
- "github.com/google/uuid"
- "github.com/rwadurian/mpc-system/services/account/domain/value_objects"
-)
-
-// AccountShare represents a mapping of key share to account
-// Note: This records share location, not share content
-type AccountShare struct {
- ID uuid.UUID
- AccountID value_objects.AccountID
- ShareType value_objects.ShareType
- PartyID string
- PartyIndex int
- DeviceType *string
- DeviceID *string
- CreatedAt time.Time
- LastUsedAt *time.Time
- IsActive bool
-}
-
-// NewAccountShare creates a new AccountShare
-func NewAccountShare(
- accountID value_objects.AccountID,
- shareType value_objects.ShareType,
- partyID string,
- partyIndex int,
-) *AccountShare {
- return &AccountShare{
- ID: uuid.New(),
- AccountID: accountID,
- ShareType: shareType,
- PartyID: partyID,
- PartyIndex: partyIndex,
- CreatedAt: time.Now().UTC(),
- IsActive: true,
- }
-}
-
-// SetDeviceInfo sets device information for user device shares
-func (s *AccountShare) SetDeviceInfo(deviceType, deviceID string) {
- s.DeviceType = &deviceType
- s.DeviceID = &deviceID
-}
-
-// UpdateLastUsed updates the last used timestamp
-func (s *AccountShare) UpdateLastUsed() {
- now := time.Now().UTC()
- s.LastUsedAt = &now
-}
-
-// Deactivate deactivates the share (e.g., when device is lost)
-func (s *AccountShare) Deactivate() {
- s.IsActive = false
-}
-
-// Activate activates the share
-func (s *AccountShare) Activate() {
- s.IsActive = true
-}
-
-// IsUserDeviceShare checks if this is a user device share
-func (s *AccountShare) IsUserDeviceShare() bool {
- return s.ShareType == value_objects.ShareTypeUserDevice
-}
-
-// IsServerShare checks if this is a server share
-func (s *AccountShare) IsServerShare() bool {
- return s.ShareType == value_objects.ShareTypeServer
-}
-
-// IsRecoveryShare checks if this is a recovery share
-func (s *AccountShare) IsRecoveryShare() bool {
- return s.ShareType == value_objects.ShareTypeRecovery
-}
-
-// Validate validates the account share
-func (s *AccountShare) Validate() error {
- if s.AccountID.IsZero() {
- return ErrShareInvalidAccountID
- }
- if !s.ShareType.IsValid() {
- return ErrShareInvalidType
- }
- if s.PartyID == "" {
- return ErrShareInvalidPartyID
- }
- if s.PartyIndex < 0 {
- return ErrShareInvalidPartyIndex
- }
- return nil
-}
-
-// AccountShare errors
-var (
- ErrShareInvalidAccountID = &AccountError{Code: "SHARE_INVALID_ACCOUNT_ID", Message: "invalid account ID"}
- ErrShareInvalidType = &AccountError{Code: "SHARE_INVALID_TYPE", Message: "invalid share type"}
- ErrShareInvalidPartyID = &AccountError{Code: "SHARE_INVALID_PARTY_ID", Message: "invalid party ID"}
- ErrShareInvalidPartyIndex = &AccountError{Code: "SHARE_INVALID_PARTY_INDEX", Message: "invalid party index"}
- ErrShareNotFound = &AccountError{Code: "SHARE_NOT_FOUND", Message: "share not found"}
-)
-
-
-
package entities
-
-import (
- "time"
-
- "github.com/google/uuid"
- "github.com/rwadurian/mpc-system/services/account/domain/value_objects"
-)
-
-// RecoverySession represents an account recovery session
-type RecoverySession struct {
- ID uuid.UUID
- AccountID value_objects.AccountID
- RecoveryType value_objects.RecoveryType
- OldShareType *value_objects.ShareType
- NewKeygenSessionID *uuid.UUID
- Status value_objects.RecoveryStatus
- RequestedAt time.Time
- CompletedAt *time.Time
-}
-
-// NewRecoverySession creates a new RecoverySession
-func NewRecoverySession(
- accountID value_objects.AccountID,
- recoveryType value_objects.RecoveryType,
-) *RecoverySession {
- return &RecoverySession{
- ID: uuid.New(),
- AccountID: accountID,
- RecoveryType: recoveryType,
- Status: value_objects.RecoveryStatusRequested,
- RequestedAt: time.Now().UTC(),
- }
-}
-
-// SetOldShareType sets the old share type being replaced
-func (r *RecoverySession) SetOldShareType(shareType value_objects.ShareType) {
- r.OldShareType = &shareType
-}
-
-// StartKeygen starts the keygen process for recovery
-func (r *RecoverySession) StartKeygen(keygenSessionID uuid.UUID) error {
- if r.Status != value_objects.RecoveryStatusRequested {
- return ErrRecoveryInvalidState
- }
- r.NewKeygenSessionID = &keygenSessionID
- r.Status = value_objects.RecoveryStatusInProgress
- return nil
-}
-
-// Complete marks the recovery as completed
-func (r *RecoverySession) Complete() error {
- if r.Status != value_objects.RecoveryStatusInProgress {
- return ErrRecoveryInvalidState
- }
- now := time.Now().UTC()
- r.CompletedAt = &now
- r.Status = value_objects.RecoveryStatusCompleted
- return nil
-}
-
-// Fail marks the recovery as failed
-func (r *RecoverySession) Fail() error {
- if r.Status == value_objects.RecoveryStatusCompleted {
- return ErrRecoveryAlreadyCompleted
- }
- r.Status = value_objects.RecoveryStatusFailed
- return nil
-}
-
-// IsCompleted checks if recovery is completed
-func (r *RecoverySession) IsCompleted() bool {
- return r.Status == value_objects.RecoveryStatusCompleted
-}
-
-// IsFailed checks if recovery failed
-func (r *RecoverySession) IsFailed() bool {
- return r.Status == value_objects.RecoveryStatusFailed
-}
-
-// IsInProgress checks if recovery is in progress
-func (r *RecoverySession) IsInProgress() bool {
- return r.Status == value_objects.RecoveryStatusInProgress
-}
-
-// Validate validates the recovery session
-func (r *RecoverySession) Validate() error {
- if r.AccountID.IsZero() {
- return ErrRecoveryInvalidAccountID
- }
- if !r.RecoveryType.IsValid() {
- return ErrRecoveryInvalidType
- }
- return nil
-}
-
-// Recovery errors
-var (
- ErrRecoveryInvalidAccountID = &AccountError{Code: "RECOVERY_INVALID_ACCOUNT_ID", Message: "invalid account ID for recovery"}
- ErrRecoveryInvalidType = &AccountError{Code: "RECOVERY_INVALID_TYPE", Message: "invalid recovery type"}
- ErrRecoveryInvalidState = &AccountError{Code: "RECOVERY_INVALID_STATE", Message: "invalid recovery state for this operation"}
- ErrRecoveryAlreadyCompleted = &AccountError{Code: "RECOVERY_ALREADY_COMPLETED", Message: "recovery already completed"}
- ErrRecoveryNotFound = &AccountError{Code: "RECOVERY_NOT_FOUND", Message: "recovery session not found"}
-)
-
-
-
package value_objects
-
-import (
- "github.com/google/uuid"
-)
-
-// AccountID represents a unique account identifier
-type AccountID struct {
- value uuid.UUID
-}
-
-// NewAccountID creates a new AccountID
-func NewAccountID() AccountID {
- return AccountID{value: uuid.New()}
-}
-
-// AccountIDFromString creates an AccountID from a string
-func AccountIDFromString(s string) (AccountID, error) {
- id, err := uuid.Parse(s)
- if err != nil {
- return AccountID{}, err
- }
- return AccountID{value: id}, nil
-}
-
-// AccountIDFromUUID creates an AccountID from a UUID
-func AccountIDFromUUID(id uuid.UUID) AccountID {
- return AccountID{value: id}
-}
-
-// String returns the string representation
-func (id AccountID) String() string {
- return id.value.String()
-}
-
-// UUID returns the UUID value
-func (id AccountID) UUID() uuid.UUID {
- return id.value
-}
-
-// IsZero checks if the AccountID is zero
-func (id AccountID) IsZero() bool {
- return id.value == uuid.Nil
-}
-
-// Equals checks if two AccountIDs are equal
-func (id AccountID) Equals(other AccountID) bool {
- return id.value == other.value
-}
-
-
-
package value_objects
-
-// AccountStatus represents the status of an account
-type AccountStatus string
-
-const (
- AccountStatusActive AccountStatus = "active"
- AccountStatusSuspended AccountStatus = "suspended"
- AccountStatusLocked AccountStatus = "locked"
- AccountStatusRecovering AccountStatus = "recovering"
-)
-
-// String returns the string representation
-func (s AccountStatus) String() string {
- return string(s)
-}
-
-// IsValid checks if the status is valid
-func (s AccountStatus) IsValid() bool {
- switch s {
- case AccountStatusActive, AccountStatusSuspended, AccountStatusLocked, AccountStatusRecovering:
- return true
- default:
- return false
- }
-}
-
-// CanLogin checks if the account can login with this status
-func (s AccountStatus) CanLogin() bool {
- return s == AccountStatusActive
-}
-
-// CanInitiateRecovery checks if recovery can be initiated
-func (s AccountStatus) CanInitiateRecovery() bool {
- return s == AccountStatusActive || s == AccountStatusLocked
-}
-
-// ShareType represents the type of key share
-type ShareType string
-
-const (
- ShareTypeUserDevice ShareType = "user_device"
- ShareTypeServer ShareType = "server"
- ShareTypeRecovery ShareType = "recovery"
-)
-
-// String returns the string representation
-func (st ShareType) String() string {
- return string(st)
-}
-
-// IsValid checks if the share type is valid
-func (st ShareType) IsValid() bool {
- switch st {
- case ShareTypeUserDevice, ShareTypeServer, ShareTypeRecovery:
- return true
- default:
- return false
- }
-}
-
-// RecoveryType represents the type of account recovery
-type RecoveryType string
-
-const (
- RecoveryTypeDeviceLost RecoveryType = "device_lost"
- RecoveryTypeShareRotation RecoveryType = "share_rotation"
-)
-
-// String returns the string representation
-func (rt RecoveryType) String() string {
- return string(rt)
-}
-
-// IsValid checks if the recovery type is valid
-func (rt RecoveryType) IsValid() bool {
- switch rt {
- case RecoveryTypeDeviceLost, RecoveryTypeShareRotation:
- return true
- default:
- return false
- }
-}
-
-// RecoveryStatus represents the status of a recovery session
-type RecoveryStatus string
-
-const (
- RecoveryStatusRequested RecoveryStatus = "requested"
- RecoveryStatusInProgress RecoveryStatus = "in_progress"
- RecoveryStatusCompleted RecoveryStatus = "completed"
- RecoveryStatusFailed RecoveryStatus = "failed"
-)
-
-// String returns the string representation
-func (rs RecoveryStatus) String() string {
- return string(rs)
-}
-
-// IsValid checks if the recovery status is valid
-func (rs RecoveryStatus) IsValid() bool {
- switch rs {
- case RecoveryStatusRequested, RecoveryStatusInProgress, RecoveryStatusCompleted, RecoveryStatusFailed:
- return true
- default:
- return false
- }
-}
-
-
-
package entities
-
-// DeviceType represents the type of device
-type DeviceType string
-
-const (
- DeviceTypeAndroid DeviceType = "android"
- DeviceTypeIOS DeviceType = "ios"
- DeviceTypePC DeviceType = "pc"
- DeviceTypeServer DeviceType = "server"
- DeviceTypeRecovery DeviceType = "recovery"
-)
-
-// DeviceInfo holds information about a participant's device
-type DeviceInfo struct {
- DeviceType DeviceType `json:"device_type"`
- DeviceID string `json:"device_id"`
- Platform string `json:"platform"`
- AppVersion string `json:"app_version"`
-}
-
-// NewDeviceInfo creates a new DeviceInfo
-func NewDeviceInfo(deviceType DeviceType, deviceID, platform, appVersion string) DeviceInfo {
- return DeviceInfo{
- DeviceType: deviceType,
- DeviceID: deviceID,
- Platform: platform,
- AppVersion: appVersion,
- }
-}
-
-// IsServer checks if the device is a server
-func (d DeviceInfo) IsServer() bool {
- return d.DeviceType == DeviceTypeServer
-}
-
-// IsMobile checks if the device is mobile
-func (d DeviceInfo) IsMobile() bool {
- return d.DeviceType == DeviceTypeAndroid || d.DeviceType == DeviceTypeIOS
-}
-
-// IsRecovery checks if the device is a recovery device
-func (d DeviceInfo) IsRecovery() bool {
- return d.DeviceType == DeviceTypeRecovery
-}
-
-// Validate validates the device info
-func (d DeviceInfo) Validate() error {
- if d.DeviceType == "" {
- return ErrInvalidDeviceInfo
- }
- return nil
-}
-
-
-
package entities
-
-import (
- "errors"
- "time"
-
- "github.com/google/uuid"
- "github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects"
-)
-
-var (
- ErrSessionFull = errors.New("session is full")
- ErrSessionExpired = errors.New("session expired")
- ErrSessionNotInProgress = errors.New("session not in progress")
- ErrParticipantNotFound = errors.New("participant not found")
- ErrInvalidSessionType = errors.New("invalid session type")
- ErrInvalidStatusTransition = errors.New("invalid status transition")
-)
-
-// SessionType represents the type of MPC session
-type SessionType string
-
-const (
- SessionTypeKeygen SessionType = "keygen"
- SessionTypeSign SessionType = "sign"
-)
-
-// IsValid checks if the session type is valid
-func (t SessionType) IsValid() bool {
- return t == SessionTypeKeygen || t == SessionTypeSign
-}
-
-// MPCSession represents an MPC session
-// Coordinator only manages session metadata, does not participate in MPC computation
-type MPCSession struct {
- ID value_objects.SessionID
- SessionType SessionType
- Threshold value_objects.Threshold
- Participants []*Participant
- Status value_objects.SessionStatus
- MessageHash []byte // Used for Sign sessions
- PublicKey []byte // Group public key after Keygen completion
- CreatedBy string
- CreatedAt time.Time
- UpdatedAt time.Time
- ExpiresAt time.Time
- CompletedAt *time.Time
-}
-
-// NewMPCSession creates a new MPC session
-func NewMPCSession(
- sessionType SessionType,
- threshold value_objects.Threshold,
- createdBy string,
- expiresIn time.Duration,
- messageHash []byte, // Only for Sign sessions
-) (*MPCSession, error) {
- if !sessionType.IsValid() {
- return nil, ErrInvalidSessionType
- }
-
- if sessionType == SessionTypeSign && len(messageHash) == 0 {
- return nil, errors.New("message hash required for sign session")
- }
-
- now := time.Now().UTC()
- return &MPCSession{
- ID: value_objects.NewSessionID(),
- SessionType: sessionType,
- Threshold: threshold,
- Participants: make([]*Participant, 0, threshold.N()),
- Status: value_objects.SessionStatusCreated,
- MessageHash: messageHash,
- CreatedBy: createdBy,
- CreatedAt: now,
- UpdatedAt: now,
- ExpiresAt: now.Add(expiresIn),
- }, nil
-}
-
-// AddParticipant adds a participant to the session
-func (s *MPCSession) AddParticipant(p *Participant) error {
- if len(s.Participants) >= s.Threshold.N() {
- return ErrSessionFull
- }
- s.Participants = append(s.Participants, p)
- s.UpdatedAt = time.Now().UTC()
- return nil
-}
-
-// GetParticipant gets a participant by party ID
-func (s *MPCSession) GetParticipant(partyID value_objects.PartyID) (*Participant, error) {
- for _, p := range s.Participants {
- if p.PartyID.Equals(partyID) {
- return p, nil
- }
- }
- return nil, ErrParticipantNotFound
-}
-
-// UpdateParticipantStatus updates a participant's status
-func (s *MPCSession) UpdateParticipantStatus(partyID value_objects.PartyID, status value_objects.ParticipantStatus) error {
- for _, p := range s.Participants {
- if p.PartyID.Equals(partyID) {
- switch status {
- case value_objects.ParticipantStatusJoined:
- return p.Join()
- case value_objects.ParticipantStatusReady:
- return p.MarkReady()
- case value_objects.ParticipantStatusCompleted:
- return p.MarkCompleted()
- case value_objects.ParticipantStatusFailed:
- p.MarkFailed()
- return nil
- default:
- return errors.New("invalid status")
- }
- }
- }
- return ErrParticipantNotFound
-}
-
-// CanStart checks if all participants have joined and the session can start
-func (s *MPCSession) CanStart() bool {
- if len(s.Participants) != s.Threshold.N() {
- return false
- }
-
- joinedCount := 0
- for _, p := range s.Participants {
- if p.IsJoined() {
- joinedCount++
- }
- }
- return joinedCount == s.Threshold.N()
-}
-
-// Start transitions the session to in_progress
-func (s *MPCSession) Start() error {
- if !s.Status.CanTransitionTo(value_objects.SessionStatusInProgress) {
- return ErrInvalidStatusTransition
- }
- if !s.CanStart() {
- return errors.New("not all participants have joined")
- }
- s.Status = value_objects.SessionStatusInProgress
- s.UpdatedAt = time.Now().UTC()
- return nil
-}
-
-// Complete marks the session as completed
-func (s *MPCSession) Complete(publicKey []byte) error {
- if !s.Status.CanTransitionTo(value_objects.SessionStatusCompleted) {
- return ErrInvalidStatusTransition
- }
- s.Status = value_objects.SessionStatusCompleted
- s.PublicKey = publicKey
- now := time.Now().UTC()
- s.CompletedAt = &now
- s.UpdatedAt = now
- return nil
-}
-
-// Fail marks the session as failed
-func (s *MPCSession) Fail() error {
- if !s.Status.CanTransitionTo(value_objects.SessionStatusFailed) {
- return ErrInvalidStatusTransition
- }
- s.Status = value_objects.SessionStatusFailed
- s.UpdatedAt = time.Now().UTC()
- return nil
-}
-
-// Expire marks the session as expired
-func (s *MPCSession) Expire() error {
- if !s.Status.CanTransitionTo(value_objects.SessionStatusExpired) {
- return ErrInvalidStatusTransition
- }
- s.Status = value_objects.SessionStatusExpired
- s.UpdatedAt = time.Now().UTC()
- return nil
-}
-
-// IsExpired checks if the session has expired
-func (s *MPCSession) IsExpired() bool {
- return time.Now().UTC().After(s.ExpiresAt)
-}
-
-// IsActive checks if the session is active
-func (s *MPCSession) IsActive() bool {
- return s.Status.IsActive() && !s.IsExpired()
-}
-
-// IsParticipant checks if a party is a participant
-func (s *MPCSession) IsParticipant(partyID value_objects.PartyID) bool {
- for _, p := range s.Participants {
- if p.PartyID.Equals(partyID) {
- return true
- }
- }
- return false
-}
-
-// AllCompleted checks if all participants have completed
-func (s *MPCSession) AllCompleted() bool {
- for _, p := range s.Participants {
- if !p.IsCompleted() {
- return false
- }
- }
- return true
-}
-
-// CompletedCount returns the number of completed participants
-func (s *MPCSession) CompletedCount() int {
- count := 0
- for _, p := range s.Participants {
- if p.IsCompleted() {
- count++
- }
- }
- return count
-}
-
-// JoinedCount returns the number of joined participants
-func (s *MPCSession) JoinedCount() int {
- count := 0
- for _, p := range s.Participants {
- if p.IsJoined() {
- count++
- }
- }
- return count
-}
-
-// GetPartyIDs returns all party IDs
-func (s *MPCSession) GetPartyIDs() []string {
- ids := make([]string, len(s.Participants))
- for i, p := range s.Participants {
- ids[i] = p.PartyID.String()
- }
- return ids
-}
-
-// GetOtherParties returns participants except the specified party
-func (s *MPCSession) GetOtherParties(excludePartyID value_objects.PartyID) []*Participant {
- others := make([]*Participant, 0, len(s.Participants)-1)
- for _, p := range s.Participants {
- if !p.PartyID.Equals(excludePartyID) {
- others = append(others, p)
- }
- }
- return others
-}
-
-// ToDTO converts to a DTO for API responses
-func (s *MPCSession) ToDTO() SessionDTO {
- participants := make([]ParticipantDTO, len(s.Participants))
- for i, p := range s.Participants {
- participants[i] = ParticipantDTO{
- PartyID: p.PartyID.String(),
- PartyIndex: p.PartyIndex,
- Status: p.Status.String(),
- DeviceType: string(p.DeviceInfo.DeviceType),
- }
- }
-
- return SessionDTO{
- ID: s.ID.String(),
- SessionType: string(s.SessionType),
- ThresholdN: s.Threshold.N(),
- ThresholdT: s.Threshold.T(),
- Participants: participants,
- Status: s.Status.String(),
- CreatedAt: s.CreatedAt,
- ExpiresAt: s.ExpiresAt,
- }
-}
-
-// SessionDTO is a data transfer object for sessions
-type SessionDTO struct {
- ID string `json:"id"`
- SessionType string `json:"session_type"`
- ThresholdN int `json:"threshold_n"`
- ThresholdT int `json:"threshold_t"`
- Participants []ParticipantDTO `json:"participants"`
- Status string `json:"status"`
- CreatedAt time.Time `json:"created_at"`
- ExpiresAt time.Time `json:"expires_at"`
-}
-
-// ParticipantDTO is a data transfer object for participants
-type ParticipantDTO struct {
- PartyID string `json:"party_id"`
- PartyIndex int `json:"party_index"`
- Status string `json:"status"`
- DeviceType string `json:"device_type"`
-}
-
-// Reconstruct reconstructs an MPCSession from database
-func ReconstructSession(
- id uuid.UUID,
- sessionType string,
- thresholdT, thresholdN int,
- status string,
- messageHash, publicKey []byte,
- createdBy string,
- createdAt, updatedAt, expiresAt time.Time,
- completedAt *time.Time,
- participants []*Participant,
-) (*MPCSession, error) {
- sessionStatus, err := value_objects.NewSessionStatus(status)
- if err != nil {
- return nil, err
- }
-
- threshold, err := value_objects.NewThreshold(thresholdT, thresholdN)
- if err != nil {
- return nil, err
- }
-
- return &MPCSession{
- ID: value_objects.SessionIDFromUUID(id),
- SessionType: SessionType(sessionType),
- Threshold: threshold,
- Participants: participants,
- Status: sessionStatus,
- MessageHash: messageHash,
- PublicKey: publicKey,
- CreatedBy: createdBy,
- CreatedAt: createdAt,
- UpdatedAt: updatedAt,
- ExpiresAt: expiresAt,
- CompletedAt: completedAt,
- }, nil
-}
-
-
-
package entities
-
-import (
- "errors"
- "time"
-
- "github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects"
-)
-
-var (
- ErrInvalidDeviceInfo = errors.New("invalid device info")
- ErrParticipantNotInvited = errors.New("participant not in invited status")
- ErrInvalidParticipant = errors.New("invalid participant")
-)
-
-// Participant represents a party in an MPC session
-type Participant struct {
- PartyID value_objects.PartyID
- PartyIndex int
- Status value_objects.ParticipantStatus
- DeviceInfo DeviceInfo
- PublicKey []byte // Party's identity public key (for authentication)
- JoinedAt time.Time
- CompletedAt *time.Time
-}
-
-// NewParticipant creates a new participant
-func NewParticipant(partyID value_objects.PartyID, partyIndex int, deviceInfo DeviceInfo) (*Participant, error) {
- if partyID.IsZero() {
- return nil, ErrInvalidParticipant
- }
- if partyIndex < 0 {
- return nil, ErrInvalidParticipant
- }
- if err := deviceInfo.Validate(); err != nil {
- return nil, err
- }
-
- return &Participant{
- PartyID: partyID,
- PartyIndex: partyIndex,
- Status: value_objects.ParticipantStatusInvited,
- DeviceInfo: deviceInfo,
- JoinedAt: time.Now().UTC(),
- }, nil
-}
-
-// Join marks the participant as joined
-func (p *Participant) Join() error {
- if !p.Status.CanTransitionTo(value_objects.ParticipantStatusJoined) {
- return errors.New("cannot transition to joined status")
- }
- p.Status = value_objects.ParticipantStatusJoined
- p.JoinedAt = time.Now().UTC()
- return nil
-}
-
-// MarkReady marks the participant as ready
-func (p *Participant) MarkReady() error {
- if !p.Status.CanTransitionTo(value_objects.ParticipantStatusReady) {
- return errors.New("cannot transition to ready status")
- }
- p.Status = value_objects.ParticipantStatusReady
- return nil
-}
-
-// MarkCompleted marks the participant as completed
-func (p *Participant) MarkCompleted() error {
- if !p.Status.CanTransitionTo(value_objects.ParticipantStatusCompleted) {
- return errors.New("cannot transition to completed status")
- }
- p.Status = value_objects.ParticipantStatusCompleted
- now := time.Now().UTC()
- p.CompletedAt = &now
- return nil
-}
-
-// MarkFailed marks the participant as failed
-func (p *Participant) MarkFailed() {
- p.Status = value_objects.ParticipantStatusFailed
-}
-
-// IsJoined checks if the participant has joined
-func (p *Participant) IsJoined() bool {
- return p.Status == value_objects.ParticipantStatusJoined ||
- p.Status == value_objects.ParticipantStatusReady ||
- p.Status == value_objects.ParticipantStatusCompleted
-}
-
-// IsReady checks if the participant is ready
-func (p *Participant) IsReady() bool {
- return p.Status == value_objects.ParticipantStatusReady ||
- p.Status == value_objects.ParticipantStatusCompleted
-}
-
-// IsCompleted checks if the participant has completed
-func (p *Participant) IsCompleted() bool {
- return p.Status == value_objects.ParticipantStatusCompleted
-}
-
-// IsFailed checks if the participant has failed
-func (p *Participant) IsFailed() bool {
- return p.Status == value_objects.ParticipantStatusFailed
-}
-
-// SetPublicKey sets the participant's public key
-func (p *Participant) SetPublicKey(publicKey []byte) {
- p.PublicKey = publicKey
-}
-
-
-
package entities
-
-import (
- "time"
-
- "github.com/google/uuid"
- "github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects"
-)
-
-// SessionMessage represents an MPC message (encrypted, Coordinator does not decrypt)
-type SessionMessage struct {
- ID uuid.UUID
- SessionID value_objects.SessionID
- FromParty value_objects.PartyID
- ToParties []value_objects.PartyID // nil means broadcast
- RoundNumber int
- MessageType string
- Payload []byte // Encrypted MPC protocol message
- CreatedAt time.Time
- DeliveredAt *time.Time
-}
-
-// NewSessionMessage creates a new session message
-func NewSessionMessage(
- sessionID value_objects.SessionID,
- fromParty value_objects.PartyID,
- toParties []value_objects.PartyID,
- roundNumber int,
- messageType string,
- payload []byte,
-) *SessionMessage {
- return &SessionMessage{
- ID: uuid.New(),
- SessionID: sessionID,
- FromParty: fromParty,
- ToParties: toParties,
- RoundNumber: roundNumber,
- MessageType: messageType,
- Payload: payload,
- CreatedAt: time.Now().UTC(),
- }
-}
-
-// IsBroadcast checks if the message is a broadcast
-func (m *SessionMessage) IsBroadcast() bool {
- return len(m.ToParties) == 0
-}
-
-// IsFor checks if the message is for a specific party
-func (m *SessionMessage) IsFor(partyID value_objects.PartyID) bool {
- if m.IsBroadcast() {
- // Broadcast is for everyone except sender
- return !m.FromParty.Equals(partyID)
- }
-
- for _, to := range m.ToParties {
- if to.Equals(partyID) {
- return true
- }
- }
- return false
-}
-
-// MarkDelivered marks the message as delivered
-func (m *SessionMessage) MarkDelivered() {
- now := time.Now().UTC()
- m.DeliveredAt = &now
-}
-
-// IsDelivered checks if the message has been delivered
-func (m *SessionMessage) IsDelivered() bool {
- return m.DeliveredAt != nil
-}
-
-// GetToPartyStrings returns to parties as strings
-func (m *SessionMessage) GetToPartyStrings() []string {
- if m.IsBroadcast() {
- return nil
- }
- result := make([]string, len(m.ToParties))
- for i, p := range m.ToParties {
- result[i] = p.String()
- }
- return result
-}
-
-// ToDTO converts to a DTO
-func (m *SessionMessage) ToDTO() MessageDTO {
- toParties := m.GetToPartyStrings()
- return MessageDTO{
- ID: m.ID.String(),
- SessionID: m.SessionID.String(),
- FromParty: m.FromParty.String(),
- ToParties: toParties,
- IsBroadcast: m.IsBroadcast(),
- RoundNumber: m.RoundNumber,
- MessageType: m.MessageType,
- Payload: m.Payload,
- CreatedAt: m.CreatedAt,
- }
-}
-
-// MessageDTO is a data transfer object for messages
-type MessageDTO struct {
- ID string `json:"id"`
- SessionID string `json:"session_id"`
- FromParty string `json:"from_party"`
- ToParties []string `json:"to_parties,omitempty"`
- IsBroadcast bool `json:"is_broadcast"`
- RoundNumber int `json:"round_number"`
- MessageType string `json:"message_type"`
- Payload []byte `json:"payload"`
- CreatedAt time.Time `json:"created_at"`
-}
-
-
-
package value_objects
-
-import (
- "errors"
- "regexp"
-)
-
-var (
- ErrInvalidPartyID = errors.New("invalid party ID")
- partyIDRegex = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
-)
-
-// PartyID represents a unique party identifier
-type PartyID struct {
- value string
-}
-
-// NewPartyID creates a new PartyID
-func NewPartyID(value string) (PartyID, error) {
- if value == "" {
- return PartyID{}, ErrInvalidPartyID
- }
- if !partyIDRegex.MatchString(value) {
- return PartyID{}, ErrInvalidPartyID
- }
- if len(value) > 255 {
- return PartyID{}, ErrInvalidPartyID
- }
- return PartyID{value: value}, nil
-}
-
-// MustNewPartyID creates a new PartyID, panics on error
-func MustNewPartyID(value string) PartyID {
- id, err := NewPartyID(value)
- if err != nil {
- panic(err)
- }
- return id
-}
-
-// String returns the string representation
-func (id PartyID) String() string {
- return id.value
-}
-
-// IsZero checks if the PartyID is zero
-func (id PartyID) IsZero() bool {
- return id.value == ""
-}
-
-// Equals checks if two PartyIDs are equal
-func (id PartyID) Equals(other PartyID) bool {
- return id.value == other.value
-}
-
-
-
package value_objects
-
-import (
- "github.com/google/uuid"
-)
-
-// SessionID represents a unique session identifier
-type SessionID struct {
- value uuid.UUID
-}
-
-// NewSessionID creates a new SessionID
-func NewSessionID() SessionID {
- return SessionID{value: uuid.New()}
-}
-
-// SessionIDFromString creates a SessionID from a string
-func SessionIDFromString(s string) (SessionID, error) {
- id, err := uuid.Parse(s)
- if err != nil {
- return SessionID{}, err
- }
- return SessionID{value: id}, nil
-}
-
-// SessionIDFromUUID creates a SessionID from a UUID
-func SessionIDFromUUID(id uuid.UUID) SessionID {
- return SessionID{value: id}
-}
-
-// String returns the string representation
-func (id SessionID) String() string {
- return id.value.String()
-}
-
-// UUID returns the UUID value
-func (id SessionID) UUID() uuid.UUID {
- return id.value
-}
-
-// IsZero checks if the SessionID is zero
-func (id SessionID) IsZero() bool {
- return id.value == uuid.Nil
-}
-
-// Equals checks if two SessionIDs are equal
-func (id SessionID) Equals(other SessionID) bool {
- return id.value == other.value
-}
-
-
-
package value_objects
-
-import (
- "errors"
-)
-
-var ErrInvalidSessionStatus = errors.New("invalid session status")
-
-// SessionStatus represents the status of an MPC session
-type SessionStatus string
-
-const (
- SessionStatusCreated SessionStatus = "created"
- SessionStatusInProgress SessionStatus = "in_progress"
- SessionStatusCompleted SessionStatus = "completed"
- SessionStatusFailed SessionStatus = "failed"
- SessionStatusExpired SessionStatus = "expired"
-)
-
-// ValidSessionStatuses contains all valid session statuses
-var ValidSessionStatuses = []SessionStatus{
- SessionStatusCreated,
- SessionStatusInProgress,
- SessionStatusCompleted,
- SessionStatusFailed,
- SessionStatusExpired,
-}
-
-// NewSessionStatus creates a new SessionStatus from string
-func NewSessionStatus(s string) (SessionStatus, error) {
- status := SessionStatus(s)
- if !status.IsValid() {
- return "", ErrInvalidSessionStatus
- }
- return status, nil
-}
-
-// String returns the string representation
-func (s SessionStatus) String() string {
- return string(s)
-}
-
-// IsValid checks if the status is valid
-func (s SessionStatus) IsValid() bool {
- for _, valid := range ValidSessionStatuses {
- if s == valid {
- return true
- }
- }
- return false
-}
-
-// CanTransitionTo checks if the status can transition to another
-func (s SessionStatus) CanTransitionTo(target SessionStatus) bool {
- transitions := map[SessionStatus][]SessionStatus{
- SessionStatusCreated: {SessionStatusInProgress, SessionStatusFailed, SessionStatusExpired},
- SessionStatusInProgress: {SessionStatusCompleted, SessionStatusFailed, SessionStatusExpired},
- SessionStatusCompleted: {},
- SessionStatusFailed: {},
- SessionStatusExpired: {},
- }
-
- allowed, ok := transitions[s]
- if !ok {
- return false
- }
-
- for _, status := range allowed {
- if status == target {
- return true
- }
- }
- return false
-}
-
-// IsTerminal checks if the status is terminal (cannot transition)
-func (s SessionStatus) IsTerminal() bool {
- return s == SessionStatusCompleted || s == SessionStatusFailed || s == SessionStatusExpired
-}
-
-// IsActive checks if the session is active
-func (s SessionStatus) IsActive() bool {
- return s == SessionStatusCreated || s == SessionStatusInProgress
-}
-
-// ParticipantStatus represents the status of a participant
-type ParticipantStatus string
-
-const (
- ParticipantStatusInvited ParticipantStatus = "invited"
- ParticipantStatusJoined ParticipantStatus = "joined"
- ParticipantStatusReady ParticipantStatus = "ready"
- ParticipantStatusCompleted ParticipantStatus = "completed"
- ParticipantStatusFailed ParticipantStatus = "failed"
-)
-
-// ValidParticipantStatuses contains all valid participant statuses
-var ValidParticipantStatuses = []ParticipantStatus{
- ParticipantStatusInvited,
- ParticipantStatusJoined,
- ParticipantStatusReady,
- ParticipantStatusCompleted,
- ParticipantStatusFailed,
-}
-
-// String returns the string representation
-func (s ParticipantStatus) String() string {
- return string(s)
-}
-
-// IsValid checks if the status is valid
-func (s ParticipantStatus) IsValid() bool {
- for _, valid := range ValidParticipantStatuses {
- if s == valid {
- return true
- }
- }
- return false
-}
-
-// CanTransitionTo checks if the status can transition to another
-func (s ParticipantStatus) CanTransitionTo(target ParticipantStatus) bool {
- transitions := map[ParticipantStatus][]ParticipantStatus{
- ParticipantStatusInvited: {ParticipantStatusJoined, ParticipantStatusFailed},
- ParticipantStatusJoined: {ParticipantStatusReady, ParticipantStatusFailed},
- ParticipantStatusReady: {ParticipantStatusCompleted, ParticipantStatusFailed},
- ParticipantStatusCompleted: {},
- ParticipantStatusFailed: {},
- }
-
- allowed, ok := transitions[s]
- if !ok {
- return false
- }
-
- for _, status := range allowed {
- if status == target {
- return true
- }
- }
- return false
-}
-
-
-
package value_objects
-
-import (
- "errors"
- "fmt"
-)
-
-var (
- ErrInvalidThreshold = errors.New("invalid threshold")
- ErrThresholdTooLarge = errors.New("threshold t cannot exceed n")
- ErrThresholdTooSmall = errors.New("threshold t must be at least 1")
- ErrNTooSmall = errors.New("n must be at least 2")
- ErrNTooLarge = errors.New("n cannot exceed maximum allowed")
-)
-
-const (
- MinN = 2
- MaxN = 10
- MinT = 1
-)
-
-// Threshold represents the t-of-n threshold configuration
-type Threshold struct {
- t int // Minimum number of parties required
- n int // Total number of parties
-}
-
-// NewThreshold creates a new Threshold value object
-func NewThreshold(t, n int) (Threshold, error) {
- if n < MinN {
- return Threshold{}, ErrNTooSmall
- }
- if n > MaxN {
- return Threshold{}, ErrNTooLarge
- }
- if t < MinT {
- return Threshold{}, ErrThresholdTooSmall
- }
- if t > n {
- return Threshold{}, ErrThresholdTooLarge
- }
- return Threshold{t: t, n: n}, nil
-}
-
-// MustNewThreshold creates a new Threshold, panics on error
-func MustNewThreshold(t, n int) Threshold {
- threshold, err := NewThreshold(t, n)
- if err != nil {
- panic(err)
- }
- return threshold
-}
-
-// T returns the minimum required parties
-func (th Threshold) T() int {
- return th.t
-}
-
-// N returns the total parties
-func (th Threshold) N() int {
- return th.n
-}
-
-// IsZero checks if the Threshold is zero
-func (th Threshold) IsZero() bool {
- return th.t == 0 && th.n == 0
-}
-
-// Equals checks if two Thresholds are equal
-func (th Threshold) Equals(other Threshold) bool {
- return th.t == other.t && th.n == other.n
-}
-
-// String returns the string representation
-func (th Threshold) String() string {
- return fmt.Sprintf("%d-of-%d", th.t, th.n)
-}
-
-// CanSign checks if the given number of parties can sign
-func (th Threshold) CanSign(availableParties int) bool {
- return availableParties >= th.t
-}
-
-// RequiresAllParties checks if all parties are required
-func (th Threshold) RequiresAllParties() bool {
- return th.t == th.n
-}
-
-
-
-
-
-
diff --git a/backend/mpc-system/coverage.out b/backend/mpc-system/coverage.out
deleted file mode 100644
index b0e512b8..00000000
--- a/backend/mpc-system/coverage.out
+++ /dev/null
@@ -1,488 +0,0 @@
-mode: atomic
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:34.12,48.2 2 21
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:51.42,54.2 2 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:57.37,61.2 3 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:64.35,65.55 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:65.55,67.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:68.2,70.12 3 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:74.32,75.55 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:75.55,77.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:78.2,80.12 3 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:84.30,87.2 2 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:90.41,91.37 1 3
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:91.37,93.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:94.2,96.12 3 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:100.87,105.2 4 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:108.35,110.2 1 4
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:113.35,115.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:118.36,119.22 1 5
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:119.22,121.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:122.2,122.19 1 4
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:122.19,124.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:125.2,125.27 1 3
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:125.27,127.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:128.2,128.54 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:128.54,130.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:131.2,131.12 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account.go:154.39,156.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:31.17,41.2 1 8
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:44.67,47.2 2 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:50.41,53.2 2 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:56.37,58.2 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:61.35,63.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:66.49,68.2 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:71.45,73.2 1 3
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:76.47,78.2 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:81.41,82.26 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:82.26,84.3 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:85.2,85.28 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:85.28,87.3 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:88.2,88.21 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:88.21,90.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:91.2,91.22 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:91.22,93.3 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/account_share.go:94.2,94.12 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:26.20,34.2 1 5
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:37.78,39.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:42.72,43.55 1 3
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:43.55,45.3 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:46.2,48.12 3 3
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:52.44,53.56 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:53.56,55.3 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:56.2,59.12 4 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:63.40,64.55 1 2
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:64.55,66.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:67.2,68.12 2 1
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:72.46,74.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:77.43,79.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:82.47,84.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:87.44,88.26 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:88.26,90.3 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:91.2,91.31 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:91.31,93.3 1 0
-github.com/rwadurian/mpc-system/services/account/domain/entities/recovery_session.go:94.2,94.12 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:13.31,15.2 1 34
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:18.55,20.16 2 2
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:20.16,22.3 1 1
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:23.2,23.34 1 1
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:27.48,29.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:32.37,34.2 1 1
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:37.38,39.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:42.35,44.2 1 4
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_id.go:47.50,49.2 1 3
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:14.40,16.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:19.39,20.11 1 5
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:21.97,22.14 1 4
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:23.10,24.15 1 1
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:29.40,31.2 1 4
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:34.51,36.2 1 3
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:48.37,50.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:53.36,54.12 1 6
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:55.63,56.14 1 5
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:57.10,58.15 1 1
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:71.40,73.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:76.39,77.12 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:78.57,79.14 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:80.10,81.15 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:96.42,98.2 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:101.41,102.12 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:103.104,104.14 1 0
-github.com/rwadurian/mpc-system/services/account/domain/value_objects/account_status.go:105.10,106.15 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:33.65,34.26 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:34.26,36.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:37.2,37.50 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:41.49,44.16 3 6
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:44.16,46.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:47.2,47.15 1 6
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:51.47,53.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:53.16,55.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:56.2,56.39 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:60.79,63.56 3 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:63.56,65.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:66.2,66.17 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:70.88,73.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:73.16,75.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:77.2,78.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:78.16,80.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:82.2,83.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:83.16,85.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:87.2,88.59 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:88.59,90.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:93.2,94.24 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:98.92,101.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:101.16,103.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:105.2,106.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:106.16,108.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:110.2,111.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:111.16,113.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:115.2,116.36 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:116.36,118.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:120.2,122.16 3 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:122.16,124.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:126.2,126.23 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:130.74,132.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:132.16,134.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:136.2,137.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:137.16,139.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:141.2,142.59 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:142.59,144.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:146.2,147.24 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:151.75,153.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:153.16,155.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:157.2,158.16 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:158.16,160.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:162.2,163.33 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:163.33,165.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:167.2,169.16 3 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:169.16,171.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:173.2,173.23 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:177.34,180.2 2 10
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:183.83,187.14 3 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:187.14,189.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:191.2,198.26 2 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:198.26,200.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:202.2,207.19 4 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:211.38,213.2 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:216.38,217.22 1 3
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:217.22,219.3 1 1
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:221.2,222.30 2 2
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:222.30,224.3 1 20
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:225.2,225.20 1 2
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:229.70,232.14 3 1
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:232.14,234.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:236.2,240.8 1 1
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:244.83,246.26 1 3
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:246.26,248.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:250.2,253.48 3 3
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:257.41,259.2 1 7
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:262.53,263.20 1 4
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:263.20,265.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:267.2,268.16 2 4
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:268.16,270.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:272.2,273.16 2 4
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:273.16,275.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:277.2,278.59 2 4
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:278.59,280.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:282.2,283.24 2 4
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:287.54,288.20 1 2
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:288.20,290.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:292.2,293.16 2 2
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:293.16,295.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:297.2,298.16 2 2
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:298.16,300.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:302.2,303.33 2 2
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:303.33,305.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:307.2,309.16 3 2
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:309.16,311.3 1 1
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:313.2,313.23 1 1
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:317.65,320.56 3 4
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:320.56,322.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:323.2,323.17 1 4
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:327.80,330.16 3 3
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:330.16,332.3 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:335.2,343.23 6 3
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:347.38,349.2 1 1
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:352.46,354.2 1 2
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:357.41,359.2 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:362.49,364.2 1 0
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:367.55,369.2 1 1
-github.com/rwadurian/mpc-system/pkg/crypto/crypto.go:372.37,374.2 1 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:35.107,42.2 1 4
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:45.118,63.2 4 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:73.83,91.2 5 4
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:94.74,110.2 4 2
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:113.73,114.104 1 11
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:114.104,115.58 1 9
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:115.58,117.4 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:118.3,118.26 1 9
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:121.2,121.16 1 11
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:121.16,122.42 1 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:122.42,124.4 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:125.3,125.30 1 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:128.2,129.25 2 8
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:129.25,131.3 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:133.2,133.20 1 8
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:137.114,139.16 2 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:139.16,141.3 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:143.2,143.32 1 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:143.32,145.3 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:147.2,147.44 1 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:147.44,149.3 1 1
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:151.2,151.31 1 2
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:151.31,153.3 1 1
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:155.2,155.20 1 1
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:159.78,161.16 2 2
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:161.16,163.3 1 1
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:165.2,165.35 1 1
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:165.35,167.3 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:170.2,170.62 1 1
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:174.90,176.16 2 5
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:176.16,178.3 1 2
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:180.2,180.34 1 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:180.34,182.3 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:184.2,188.8 1 3
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:192.80,194.16 2 1
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:194.16,196.3 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:198.2,198.35 1 1
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:198.35,200.3 1 0
-github.com/rwadurian/mpc-system/pkg/jwt/jwt.go:202.2,202.20 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:15.29,17.2 1 4
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:20.45,22.2 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:25.40,27.16 2 0
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:27.16,28.13 1 0
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:30.2,30.11 1 0
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:34.33,37.2 2 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:40.44,42.2 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:45.49,47.2 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:50.25,52.2 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:55.38,57.2 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:60.26,63.2 2 0
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:66.39,67.14 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:67.14,69.3 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:70.2,71.17 2 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:71.17,73.3 1 0
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:74.2,74.17 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:74.17,78.3 3 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:79.2,79.10 1 0
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:83.39,85.2 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:88.61,89.26 1 3
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:89.26,90.17 1 5
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:90.17,92.4 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:94.2,94.14 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:98.63,100.26 2 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:100.26,101.17 1 6
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:101.17,103.4 1 5
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:105.2,105.15 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:109.45,112.26 3 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:112.26,113.28 1 9
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:113.28,116.4 2 6
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:118.2,118.15 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:122.50,123.22 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:123.22,125.3 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:126.2,126.19 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:130.35,131.14 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:131.14,133.3 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:134.2,134.11 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:138.34,140.2 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:143.25,145.2 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:148.28,150.2 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:153.33,155.2 1 0
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:158.44,160.27 2 3
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:160.27,161.16 1 9
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:161.16,163.4 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:165.2,165.13 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:169.50,171.19 2 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:171.19,173.3 1 3
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:174.2,174.13 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:178.52,180.22 2 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:180.22,182.3 1 3
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:183.2,183.15 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:187.48,188.11 1 3
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:188.11,190.3 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:191.2,191.10 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:195.48,196.11 1 3
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:196.11,198.3 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:199.2,199.10 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:203.61,204.17 1 3
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:204.17,206.3 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:207.2,207.17 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:207.17,209.3 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:210.2,210.14 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:214.86,216.2 1 0
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:219.49,220.27 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:220.27,222.3 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:223.2,223.87 1 1
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:227.69,229.32 2 3
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:229.32,230.28 1 7
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:230.28,232.4 1 2
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:233.3,233.21 1 5
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:233.21,236.4 2 4
-github.com/rwadurian/mpc-system/pkg/utils/utils.go:238.2,238.12 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/device_info.go:23.93,30.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/device_info.go:33.37,35.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/device_info.go:38.37,40.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/device_info.go:43.39,45.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/device_info.go:48.38,49.24 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/device_info.go:49.24,51.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/device_info.go:52.2,52.12 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:29.37,31.2 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:57.24,58.28 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:58.28,60.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:62.2,62.61 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:62.61,64.3 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:66.2,78.8 2 6
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:82.59,83.44 1 4
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:83.44,85.3 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:86.2,88.12 3 3
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:92.90,93.35 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:93.35,94.32 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:94.32,96.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:98.2,98.36 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:102.123,103.35 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:103.35,104.32 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:104.32,105.18 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:106.47,107.20 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:108.46,109.25 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:110.50,111.29 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:112.47,114.15 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:115.12,116.40 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:120.2,120.31 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:124.38,125.44 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:125.44,127.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:129.2,130.35 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:130.35,131.19 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:131.19,133.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:135.2,135.39 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:139.36,140.70 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:140.70,142.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:143.2,143.19 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:143.19,145.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:146.2,148.12 3 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:152.55,153.69 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:153.69,155.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:156.2,161.12 6 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:165.35,166.66 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:166.66,168.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:169.2,171.12 3 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:175.37,176.67 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:176.67,178.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:179.2,181.12 3 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:185.39,187.2 1 2
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:190.38,192.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:195.72,196.35 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:196.35,197.32 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:197.32,199.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:201.2,201.14 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:205.42,206.35 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:206.35,207.23 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:207.23,209.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:211.2,211.13 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:215.43,217.35 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:217.35,218.22 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:218.22,220.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:222.2,222.14 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:226.40,228.35 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:228.35,229.19 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:229.19,231.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:233.2,233.14 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:237.45,239.35 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:239.35,241.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:242.2,242.12 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:246.91,248.35 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:248.35,249.40 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:249.40,251.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:253.2,253.15 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:257.41,259.35 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:259.35,266.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:268.2,277.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:311.24,313.16 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:313.16,315.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:317.2,318.16 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:318.16,320.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/mpc_session.go:322.2,335.8 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:28.113,29.22 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:29.22,31.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:32.2,32.20 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:32.20,34.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:35.2,35.46 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:35.46,37.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:39.2,45.8 1 7
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:49.36,50.70 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:50.70,52.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:53.2,55.12 3 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:59.41,60.69 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:60.69,62.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:63.2,64.12 2 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:68.45,69.73 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:69.73,71.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:72.2,75.12 4 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:79.36,81.2 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:84.39,88.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:91.38,94.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:97.42,99.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:102.39,104.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/participant.go:107.54,109.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:31.19,42.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:45.45,47.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:50.68,51.21 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:51.21,54.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:56.2,56.33 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:56.33,57.25 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:57.25,59.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:61.2,61.14 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:65.42,68.2 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:71.45,73.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:76.55,77.21 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:77.21,79.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:80.2,81.32 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:81.32,83.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:84.2,84.15 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities/session_message.go:88.45,101.2 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:19.48,20.17 1 12
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:20.17,22.3 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:23.2,23.38 1 11
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:23.38,25.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:26.2,26.22 1 11
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:26.22,28.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:29.2,29.35 1 11
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:33.43,35.16 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:35.16,36.13 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:38.2,38.11 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:42.35,44.2 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:47.33,49.2 1 8
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/party_id.go:52.46,54.2 1 2
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:13.31,15.2 1 8
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:18.55,20.16 2 2
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:20.16,22.3 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:23.2,23.34 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:27.48,29.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:32.37,34.2 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:37.38,39.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:42.35,44.2 1 2
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_id.go:47.50,49.2 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:30.56,32.23 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:32.23,34.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:35.2,35.20 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:39.40,41.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:44.39,45.45 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:45.45,46.17 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:46.17,48.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:50.2,50.14 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:54.67,64.9 3 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:64.9,66.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:68.2,68.33 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:68.33,69.23 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:69.23,71.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:73.2,73.14 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:77.42,79.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:82.40,84.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:107.44,109.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:112.43,113.49 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:113.49,114.17 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:114.17,116.4 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:118.2,118.14 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:122.75,132.9 3 3
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:132.9,134.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:136.2,136.33 1 3
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:136.33,137.23 1 3
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:137.23,139.4 1 3
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/session_status.go:141.2,141.14 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:29.48,30.14 1 11
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:30.14,32.3 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:33.2,33.14 1 10
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:33.14,35.3 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:36.2,36.14 1 10
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:36.14,38.3 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:39.2,39.11 1 9
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:39.11,41.3 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:42.2,42.35 1 8
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:46.43,48.16 2 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:48.16,49.13 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:51.2,51.18 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:55.29,57.2 1 2
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:60.29,62.2 1 12
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:65.35,67.2 1 1
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:70.50,72.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:75.37,77.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:80.56,82.2 1 0
-github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects/threshold.go:85.47,87.2 1 0