feature/refactor did state (#10)

* feat(did): remove account types

* feat: Refactor Property to Proof in zkprop.go

* feat: add ZKP proof mechanism for verifications

* fix: return bool and error from pinInitialVault

* feat: implement KeyshareSet for managing user and validator keyshares

* feat: Update Credential type in protobuf

* feat: update credential schema with sign count

* feat: migrate  and  modules to middleware

* refactor: rename vault module to ORM

* chore(dwn): add service worker registration to index template

* feat: integrate service worker for offline functionality

* refactor(did): use DIDNamespace enum for verification method in proto reflection

* refactor: update protobuf definitions to support Keyshare

* feat: expose did keeper in app keepers

* Add Motr Web App

* refactor: rename motr/handlers/discovery.go to motr/handlers/openid.go

* refactor: move session related code to middleware

* feat: add database operations for managing assets, chains, and credentials

* feat: add htmx support for UI updates

* refactor: extract common helper scripts

* chore: remove unused storage GUI components

* refactor: Move frontend rendering to dedicated handlers

* refactor: rename  to

* refactor: move alert implementation to templ

* feat: add alert component with icon, title, and message

* feat: add new RequestHeaders struct to store request headers

* Feature/create home view (#9)

* refactor: move view logic to new htmx handler

* refactor: remove unnecessary dependencies

* refactor: remove unused dependencies

* feat(devbox): integrate air for local development

* feat: implement openid connect discovery document

* refactor: rename  to

* refactor(did): update service handling to support DNS discovery

* feat: add support for user and validator keyshares

* refactor: move keyshare signing logic to signer
This commit is contained in:
Prad Nukala
2024-09-11 15:10:54 -04:00
committed by GitHub
parent 4f2d342649
commit bbfe2a2329
197 changed files with 14668 additions and 27810 deletions
+148 -73
View File
@@ -4,12 +4,103 @@ import (
"encoding/base64"
"fmt"
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/protocol/webauthncose"
didv1 "github.com/onsonr/sonr/api/did/v1"
"github.com/onsonr/sonr/x/did/types"
)
func FormatEC2PublicKey(key *webauthncose.EC2PublicKeyData) (*types.JWK, error) {
func APIFormatDIDNamespace(namespace types.DIDNamespace) didv1.DIDNamespace {
return didv1.DIDNamespace(namespace)
}
func APIFormatDIDNamespaces(namespaces []types.DIDNamespace) []didv1.DIDNamespace {
var s []didv1.DIDNamespace
for _, namespace := range namespaces {
s = append(s, APIFormatDIDNamespace(namespace))
}
return s
}
func APIFormatKeyRole(role types.KeyRole) didv1.KeyRole {
return didv1.KeyRole(role)
}
func APIFormatKeyAlgorithm(algorithm types.KeyAlgorithm) didv1.KeyAlgorithm {
return didv1.KeyAlgorithm(algorithm)
}
func APIFormatKeyEncoding(encoding types.KeyEncoding) didv1.KeyEncoding {
return didv1.KeyEncoding(encoding)
}
func APIFormatKeyCurve(curve types.KeyCurve) didv1.KeyCurve {
return didv1.KeyCurve(curve)
}
func APIFormatKeyType(keyType types.KeyType) didv1.KeyType {
return didv1.KeyType(keyType)
}
func APIFormatPermissions(permissions *types.Permissions) *didv1.Permissions {
if permissions == nil {
return nil
}
p := didv1.Permissions{
Grants: APIFormatDIDNamespaces(permissions.Grants),
Scopes: APIFormatPermissionScopes(permissions.Scopes),
}
return &p
}
func APIFormatPermissionScope(scope types.PermissionScope) didv1.PermissionScope {
return didv1.PermissionScope(scope)
}
func APIFormatPermissionScopes(scopes []types.PermissionScope) []didv1.PermissionScope {
var s []didv1.PermissionScope
for _, scope := range scopes {
s = append(s, APIFormatPermissionScope(scope))
}
return s
}
func APIFormatServiceRecord(service *types.Service) *didv1.ServiceRecord {
return &didv1.ServiceRecord{
Id: service.Id,
ServiceType: service.ServiceType,
Authority: service.Authority,
Origin: service.Origin,
Description: service.Description,
ServiceEndpoints: service.ServiceEndpoints,
Permissions: APIFormatPermissions(service.Permissions),
}
}
func APIFormatPubKeyJWK(jwk *types.PubKey_JWK) *didv1.PubKey_JWK {
return &didv1.PubKey_JWK{
Kty: jwk.Kty,
Crv: jwk.Crv,
X: jwk.X,
Y: jwk.Y,
N: jwk.N,
E: jwk.E,
}
}
func APIFormatPubKey(key *types.PubKey) *didv1.PubKey {
return &didv1.PubKey{
Role: APIFormatKeyRole(key.GetRole()),
Algorithm: APIFormatKeyAlgorithm(key.GetAlgorithm()),
Encoding: APIFormatKeyEncoding(key.GetEncoding()),
Curve: APIFormatKeyCurve(key.GetCurve()),
KeyType: APIFormatKeyType(key.GetKeyType()),
Raw: key.GetRaw(),
}
}
func FormatEC2PublicKey(key *webauthncose.EC2PublicKeyData) (*types.PubKey_JWK, error) {
curve, err := GetCOSECurveName(key.Curve)
if err != nil {
return nil, err
@@ -25,7 +116,7 @@ func FormatEC2PublicKey(key *webauthncose.EC2PublicKeyData) (*types.JWK, error)
return MapToJWK(jwkMap)
}
func FormatRSAPublicKey(key *webauthncose.RSAPublicKeyData) (*types.JWK, error) {
func FormatRSAPublicKey(key *webauthncose.RSAPublicKeyData) (*types.PubKey_JWK, error) {
jwkMap := map[string]interface{}{
"kty": "RSA",
"n": base64.RawURLEncoding.EncodeToString(key.Modulus),
@@ -35,8 +126,8 @@ func FormatRSAPublicKey(key *webauthncose.RSAPublicKeyData) (*types.JWK, error)
return MapToJWK(jwkMap)
}
func FormatOKPPublicKey(key *webauthncose.OKPPublicKeyData) (*types.JWK, error) {
curve, err := getOKPCurveName(key.Curve)
func FormatOKPPublicKey(key *webauthncose.OKPPublicKeyData) (*types.PubKey_JWK, error) {
curve, err := GetOKPCurveName(key.Curve)
if err != nil {
return nil, err
}
@@ -50,8 +141,8 @@ func FormatOKPPublicKey(key *webauthncose.OKPPublicKeyData) (*types.JWK, error)
return MapToJWK(jwkMap)
}
func MapToJWK(m map[string]interface{}) (*types.JWK, error) {
jwk := &types.JWK{}
func MapToJWK(m map[string]interface{}) (*types.PubKey_JWK, error) {
jwk := &types.PubKey_JWK{}
for k, v := range m {
switch k {
case "kty":
@@ -84,7 +175,7 @@ func GetCOSECurveName(curveID int64) (string, error) {
}
}
func getOKPCurveName(curveID int64) (string, error) {
func GetOKPCurveName(curveID int64) (string, error) {
switch curveID {
case int64(webauthncose.Ed25519):
return "Ed25519", nil
@@ -93,84 +184,68 @@ func getOKPCurveName(curveID int64) (string, error) {
}
}
func ModulePubKeyToAPI(pk *types.PubKey) *didv1.PubKey {
return &didv1.PubKey{
Role: ModuleKeyRoleToAPI(pk.GetRole()),
Algorithm: ModuleKeyAlgorithmToAPI(pk.GetAlgorithm()),
Encoding: ModuleKeyEncodingToAPI(pk.GetEncoding()),
Curve: ModuleKeyCurveToAPI(pk.GetCurve()),
KeyType: ModuleKeyTypeToAPI(pk.GetKeyType()),
Raw: pk.GetRaw(),
// NormalizeTransports returns the transports as strings
func NormalizeTransports(transports []protocol.AuthenticatorTransport) []string {
tss := make([]string, len(transports))
for i, t := range transports {
tss[i] = string(t)
}
return tss
}
// GetTransports returns the protocol.AuthenticatorTransport
func ModuleTransportsToProtocol(transport []string) []protocol.AuthenticatorTransport {
tss := make([]protocol.AuthenticatorTransport, len(transport))
for i, t := range transport {
tss[i] = protocol.AuthenticatorTransport(t)
}
return tss
}
// ModuleFormatAPIServiceRecord formats a service record for the module
func ModuleFormatAPIServiceRecord(service *didv1.ServiceRecord) *types.Service {
return &types.Service{
Id: service.Id,
ServiceType: service.ServiceType,
Authority: service.Authority,
Origin: service.Origin,
Description: service.Description,
ServiceEndpoints: service.ServiceEndpoints,
Permissions: ModuleFormatAPIPermissions(service.Permissions),
}
}
func ModuleKeyRoleToAPI(role types.KeyRole) didv1.KeyRole {
switch role {
case types.KeyRole_KEY_ROLE_INVOCATION:
return didv1.KeyRole_KEY_ROLE_INVOCATION
case types.KeyRole_KEY_ROLE_ASSERTION:
return didv1.KeyRole_KEY_ROLE_ASSERTION
case types.KeyRole_KEY_ROLE_DELEGATION:
return didv1.KeyRole_KEY_ROLE_DELEGATION
default:
return didv1.KeyRole_KEY_ROLE_INVOCATION
func ModuleFormatAPIPermissions(permissions *didv1.Permissions) *types.Permissions {
if permissions == nil {
return nil
}
p := types.Permissions{
Grants: ModuleFormatAPIDIDNamespaces(permissions.Grants),
Scopes: ModuleFormatAPIPermissionScopes(permissions.Scopes),
}
return &p
}
func ModuleKeyAlgorithmToAPI(algorithm types.KeyAlgorithm) didv1.KeyAlgorithm {
switch algorithm {
case types.KeyAlgorithm_KEY_ALGORITHM_ES256K:
return didv1.KeyAlgorithm_KEY_ALGORITHM_ES256K
case types.KeyAlgorithm_KEY_ALGORITHM_ES256:
return didv1.KeyAlgorithm_KEY_ALGORITHM_ES256
case types.KeyAlgorithm_KEY_ALGORITHM_ES384:
return didv1.KeyAlgorithm_KEY_ALGORITHM_ES384
case types.KeyAlgorithm_KEY_ALGORITHM_ES512:
return didv1.KeyAlgorithm_KEY_ALGORITHM_ES512
case types.KeyAlgorithm_KEY_ALGORITHM_EDDSA:
return didv1.KeyAlgorithm_KEY_ALGORITHM_EDDSA
default:
return didv1.KeyAlgorithm_KEY_ALGORITHM_ES256K
}
func ModuleFormatAPIPermissionScope(scope didv1.PermissionScope) types.PermissionScope {
return types.PermissionScope(scope)
}
func ModuleKeyCurveToAPI(curve types.KeyCurve) didv1.KeyCurve {
switch curve {
case types.KeyCurve_KEY_CURVE_P256:
return didv1.KeyCurve_KEY_CURVE_P256
case types.KeyCurve_KEY_CURVE_SECP256K1:
return didv1.KeyCurve_KEY_CURVE_SECP256K1
case types.KeyCurve_KEY_CURVE_BLS12381:
return didv1.KeyCurve_KEY_CURVE_BLS12381
case types.KeyCurve_KEY_CURVE_KECCAK256:
return didv1.KeyCurve_KEY_CURVE_KECCAK256
default:
return didv1.KeyCurve_KEY_CURVE_P256
func ModuleFormatAPIPermissionScopes(scopes []didv1.PermissionScope) []types.PermissionScope {
var s []types.PermissionScope
for _, scope := range scopes {
s = append(s, ModuleFormatAPIPermissionScope(scope))
}
return s
}
func ModuleKeyEncodingToAPI(encoding types.KeyEncoding) didv1.KeyEncoding {
switch encoding {
case types.KeyEncoding_KEY_ENCODING_RAW:
return didv1.KeyEncoding_KEY_ENCODING_RAW
case types.KeyEncoding_KEY_ENCODING_HEX:
return didv1.KeyEncoding_KEY_ENCODING_HEX
case types.KeyEncoding_KEY_ENCODING_MULTIBASE:
return didv1.KeyEncoding_KEY_ENCODING_MULTIBASE
default:
return didv1.KeyEncoding_KEY_ENCODING_RAW
}
func ModuleFormatAPIDIDNamespace(namespace didv1.DIDNamespace) types.DIDNamespace {
return types.DIDNamespace(namespace)
}
func ModuleKeyTypeToAPI(keyType types.KeyType) didv1.KeyType {
switch keyType {
case types.KeyType_KEY_TYPE_BIP32:
return didv1.KeyType_KEY_TYPE_BIP32
case types.KeyType_KEY_TYPE_ZK:
return didv1.KeyType_KEY_TYPE_ZK
case types.KeyType_KEY_TYPE_WEBAUTHN:
return didv1.KeyType_KEY_TYPE_WEBAUTHN
default:
return didv1.KeyType_KEY_TYPE_BIP32
func ModuleFormatAPIDIDNamespaces(namespaces []didv1.DIDNamespace) []types.DIDNamespace {
var s []types.DIDNamespace
for _, namespace := range namespaces {
s = append(s, ModuleFormatAPIDIDNamespace(namespace))
}
return s
}
+48
View File
@@ -0,0 +1,48 @@
package builder
import (
"net/http"
"github.com/labstack/echo/v4"
"gopkg.in/macaroon.v2"
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
)
var PermissionNamespace *checkers.Namespace
func ValidateMacaroonMiddleware(secretKey []byte, location string) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Extract the macaroon from the Authorization header
auth := c.Request().Header.Get("Authorization")
if auth == "" {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Missing Authorization header"})
}
// Decode the macaroon
mac, err := macaroon.Base64Decode([]byte(auth))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid macaroon encoding"})
}
token, err := macaroon.New(secretKey, mac, location, macaroon.LatestVersion)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid macaroon"})
}
// Verify the macaroon
err = token.Verify(secretKey, func(caveat string) error {
// Implement your caveat verification logic here
// For example, you might check if the caveat is still valid (e.g., not expired)
return nil // Return nil if the caveat is valid
}, nil)
if err != nil {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Invalid macaroon"})
}
// Macaroon is valid, proceed to the next handler
return next(c)
}
}
}
+1 -1
View File
@@ -52,7 +52,7 @@ type PublicKeyCredentialCreationOptions struct {
Extensions AuthenticationExtensions `json:"extensions,omitempty"`
}
func NewRegistrationOptions(origin string, subject string, vaultCID string, params *types.Params) (*PublicKeyCredentialCreationOptions, error) {
func GetPublicKeyCredentialCreationOptions(origin string, subject string, vaultCID string, params *types.Params) (*PublicKeyCredentialCreationOptions, error) {
chal, err := CreateChallenge()
if err != nil {
return nil, err
+8 -7
View File
@@ -4,6 +4,7 @@ import (
"fmt"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
didv1 "github.com/onsonr/sonr/api/did/v1"
"github.com/onsonr/sonr/x/did/types"
"github.com/go-webauthn/webauthn/protocol/webauthncose"
@@ -33,17 +34,17 @@ func CreateAuthnVerification(namespace types.DIDNamespace, issuer string, contro
}
// CreateWalletVerification creates a new verification method for a wallet
func CreateWalletVerification(namespace types.DIDNamespace, controller string, pubkey *types.PubKey, identifier string) *types.VerificationMethod {
return &types.VerificationMethod{
Method: namespace,
func CreateWalletVerification(namespace types.DIDNamespace, controller string, pubkey *types.PubKey, identifier string) *didv1.VerificationMethod {
return &didv1.VerificationMethod{
Method: APIFormatDIDNamespace(namespace),
Controller: controller,
PublicKey: pubkey,
PublicKey: APIFormatPubKey(pubkey),
Id: identifier,
}
}
// ExtractWebAuthnPublicKey parses the raw public key bytes and returns a JWK representation
func ExtractWebAuthnPublicKey(keyBytes []byte) (*types.JWK, error) {
func ExtractWebAuthnPublicKey(keyBytes []byte) (*types.PubKey_JWK, error) {
key, err := webauthncose.ParsePublicKey(keyBytes)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
@@ -62,8 +63,8 @@ func ExtractWebAuthnPublicKey(keyBytes []byte) (*types.JWK, error) {
}
// NewInitialWalletAccounts creates a new set of verification methods for a wallet
func NewInitialWalletAccounts(controller string, pubkey *types.PubKey) ([]*types.VerificationMethod, error) {
var verificationMethods []*types.VerificationMethod
func NewInitialWalletAccounts(controller string, pubkey *types.PubKey) ([]*didv1.VerificationMethod, error) {
var verificationMethods []*didv1.VerificationMethod
for method, chain := range types.InitialChainCodes {
nk, err := computeBip32AccountPublicKey(pubkey, chain, 0)
if err != nil {
+56
View File
@@ -0,0 +1,56 @@
package builder
import (
"github.com/onsonr/sonr/x/did/types"
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
)
var (
GenericPermissionScopeStrings = [...]string{
"profile.name",
"identifiers.email",
"identifiers.phone",
"transactions.read",
"transactions.write",
"wallets.read",
"wallets.create",
"wallets.subscribe",
"wallets.update",
"transactions.verify",
"transactions.broadcast",
"admin.user",
"admin.validator",
}
StringToModulePermissionScope = map[string]types.PermissionScope{
"PERMISSION_SCOPE_UNSPECIFIED": types.PermissionScope_PERMISSION_SCOPE_UNSPECIFIED,
"PERMISSION_SCOPE_BASIC_INFO": types.PermissionScope_PERMISSION_SCOPE_BASIC_INFO,
"PERMISSION_SCOPE_IDENTIFIERS_EMAIL": types.PermissionScope_PERMISSION_SCOPE_PERMISSIONS_READ,
"PERMISSION_SCOPE_IDENTIFIERS_PHONE": types.PermissionScope_PERMISSION_SCOPE_PERMISSIONS_WRITE,
"PERMISSION_SCOPE_TRANSACTIONS_READ": types.PermissionScope_PERMISSION_SCOPE_TRANSACTIONS_READ,
"PERMISSION_SCOPE_TRANSACTIONS_WRITE": types.PermissionScope_PERMISSION_SCOPE_TRANSACTIONS_WRITE,
"PERMISSION_SCOPE_WALLETS_READ": types.PermissionScope_PERMISSION_SCOPE_WALLETS_READ,
"PERMISSION_SCOPE_WALLETS_CREATE": types.PermissionScope_PERMISSION_SCOPE_WALLETS_CREATE,
"PERMISSION_SCOPE_WALLETS_SUBSCRIBE": types.PermissionScope_PERMISSION_SCOPE_WALLETS_SUBSCRIBE,
"PERMISSION_SCOPE_WALLETS_UPDATE": types.PermissionScope_PERMISSION_SCOPE_WALLETS_UPDATE,
"PERMISSION_SCOPE_TRANSACTIONS_VERIFY": types.PermissionScope_PERMISSION_SCOPE_TRANSACTIONS_VERIFY,
"PERMISSION_SCOPE_TRANSACTIONS_BROADCAST": types.PermissionScope_PERMISSION_SCOPE_TRANSACTIONS_BROADCAST,
"PERMISSION_SCOPE_ADMIN_USER": types.PermissionScope_PERMISSION_SCOPE_ADMIN_USER,
"PERMISSION_SCOPE_ADMIN_VALIDATOR": types.PermissionScope_PERMISSION_SCOPE_ADMIN_VALIDATOR,
}
)
func ResolvePermissionScope(scope string) (types.PermissionScope, bool) {
uriToPrefix := make(map[string]string)
for _, scope := range GenericPermissionScopeStrings {
uriToPrefix["https://example.com/auth/"+scope] = scope
}
PermissionNamespace := checkers.NewNamespace(uriToPrefix)
prefix, ok := PermissionNamespace.Resolve("https://example.com/auth/" + scope)
if !ok {
return 0, false
}
permScope, ok := StringToModulePermissionScope[prefix]
return permScope, ok
}
+59
View File
@@ -0,0 +1,59 @@
package builder
import (
"github.com/onsonr/crypto"
"github.com/onsonr/sonr/x/did/types"
)
type Signer interface {
Sign(msg []byte) ([]byte, error)
Verify(msg []byte, sig []byte) error
PublicKey() []byte
}
type signer struct {
user *types.Keyshare
val *types.Keyshare
}
func (k signer) Sign(msg []byte) ([]byte, error) {
valSignFunc, err := crypto.GetSignFunc(k.val, msg)
if err != nil {
return nil, err
}
usrSignFunc, err := crypto.GetSignFunc(k.user, msg)
if err != nil {
return nil, err
}
sig, err := crypto.RunMPCSign(valSignFunc, usrSignFunc)
if err != nil {
return nil, err
}
return crypto.SerializeMPCSignature(sig)
}
func (k signer) Verify(msg []byte, sig []byte) error {
sigMpc, err := crypto.DeserializeMPCSignature(sig)
if err != nil {
return err
}
pk, err := crypto.GetECDSAPublicKey(k.val)
if err != nil {
return err
}
ok := crypto.VerifyMPCSignature(sigMpc, msg, pk)
if !ok {
return types.ErrInvalidSignature
}
return nil
}
func (k signer) PublicKey() []byte {
if k.user != nil {
return k.user.PublicKey
}
if k.val != nil {
return k.val.PublicKey
}
return nil
}
+55
View File
@@ -4,8 +4,63 @@ import (
"bytes"
"encoding/base64"
"reflect"
"github.com/go-webauthn/webauthn/protocol"
)
// Credential contains all needed information about a WebAuthn credential for storage.
type Credential struct {
Subject string `json:"handle"`
AttestationType string `json:"attestationType"`
Origin string `json:"origin"`
CredentialID []byte `json:"id"`
PublicKey []byte `json:"publicKey"`
Transport []string `json:"transport"`
SignCount uint32 `json:"signCount"`
UserPresent bool `json:"userPresent"`
UserVerified bool `json:"userVerified"`
BackupEligible bool `json:"backupEligible"`
BackupState bool `json:"backupState"`
CloneWarning bool `json:"cloneWarning"`
}
// NewCredential will return a credential pointer on successful validation of a registration response.
func NewCredential(c *protocol.ParsedCredentialCreationData, origin, handle string) *Credential {
return &Credential{
Subject: handle,
Origin: origin,
AttestationType: c.Response.AttestationObject.Format,
CredentialID: c.Response.AttestationObject.AuthData.AttData.CredentialID,
PublicKey: c.Response.AttestationObject.AuthData.AttData.CredentialPublicKey,
Transport: NormalizeTransports(c.Response.Transports),
SignCount: c.Response.AttestationObject.AuthData.Counter,
UserPresent: c.Response.AttestationObject.AuthData.Flags.HasUserPresent(),
UserVerified: c.Response.AttestationObject.AuthData.Flags.HasUserVerified(),
BackupEligible: c.Response.AttestationObject.AuthData.Flags.HasBackupEligible(),
BackupState: c.Response.AttestationObject.AuthData.Flags.HasAttestedCredentialData(),
}
}
// Descriptor converts a Credential into a protocol.CredentialDescriptor.
func (c *Credential) Descriptor() protocol.CredentialDescriptor {
return protocol.CredentialDescriptor{
Type: protocol.PublicKeyCredentialType,
CredentialID: c.CredentialID,
Transport: ModuleTransportsToProtocol(c.Transport),
AttestationType: c.AttestationType,
}
}
// This is a signal that the authenticator may be cloned, see CloneWarning above for more information.
func (a *Credential) UpdateCounter(authDataCount uint32) {
if authDataCount <= a.SignCount && (authDataCount != 0 || a.SignCount != 0) {
a.CloneWarning = true
return
}
a.SignCount = authDataCount
}
type CredentialDescriptor struct {
// The valid credential types.
Type CredentialType `json:"type"`
+1
View File
@@ -0,0 +1 @@
package context
@@ -1,4 +1,4 @@
package middleware
package context
import (
"context"
+60
View File
@@ -0,0 +1,60 @@
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/onsonr/sonr/x/did/builder"
"github.com/onsonr/sonr/x/did/types"
"google.golang.org/grpc/peer"
)
type Context struct {
SDKCtx sdk.Context
Keeper Keeper
Peer *peer.Peer
}
func (k Keeper) CurrentCtx(goCtx context.Context) Context {
ctx := sdk.UnwrapSDKContext(goCtx)
peer, _ := peer.FromContext(goCtx)
return Context{SDKCtx: ctx, Peer: peer, Keeper: k}
}
func (c Context) Params() *types.Params {
return c.Keeper.GetParams(c.SDK())
}
func (c Context) SDK() sdk.Context {
return c.SDKCtx
}
func (c Context) IsAnonymous() bool {
if c.Peer == nil {
return true
}
return c.Peer.Addr == nil
}
func (c Context) PeerID() string {
if c.Peer == nil {
return ""
}
return c.Peer.Addr.String()
}
func (c Context) GetService(origin string) (*types.Service, error) {
rec, err := c.Keeper.OrmDB.ServiceRecordTable().GetByOrigin(c.SDK(), origin)
if err != nil {
return nil, err
}
return builder.ModuleFormatAPIServiceRecord(rec), nil
}
func (c Context) GetServiceInfo(origin string) *types.ServiceInfo {
rec, _ := c.GetService(origin)
if rec == nil {
return &types.ServiceInfo{Exists: false, Origin: origin, Fingerprint: types.ComputeOriginTXTRecord(origin)}
}
return &types.ServiceInfo{Exists: true, Origin: origin, Fingerprint: types.ComputeOriginTXTRecord(origin), Service: rec}
}
+2 -1
View File
@@ -66,7 +66,8 @@ func (k Keeper) GetParams(ctx sdk.Context) *types.Params {
if err != nil {
p = types.DefaultParams()
}
return &p
params := p.ActiveParams(k.HasIPFSConnection())
return &params
}
// GetExpirationBlockHeight returns the block height at which the given duration will have passed
+4 -4
View File
@@ -23,11 +23,11 @@ func (k Keeper) assembleInitialVault(ctx sdk.Context) (string, int64, error) {
}
// pinInitialVault pins the initial vault to the local IPFS node
func (k Keeper) pinInitialVault(_ sdk.Context, cid string, address string) error {
func (k Keeper) pinInitialVault(_ sdk.Context, cid string, address string) (bool, error) {
// Resolve the path
path, err := path.NewPath(cid)
if err != nil {
return err
return false, err
}
// 1. Initialize vault.db sqlite database in local IPFS with Mount
@@ -37,13 +37,13 @@ func (k Keeper) pinInitialVault(_ sdk.Context, cid string, address string) error
// 3. Publish the path to the IPNS
_, err = k.ipfsClient.Name().Publish(context.Background(), path, options.Name.Key(address))
if err != nil {
return err
return false, err
}
// 4. Insert the accounts into x/auth
// 5. Insert the controller into state
return nil
return true, nil
}
// GetFromIPFS gets a file from the local IPFS node
+3 -3
View File
@@ -14,7 +14,7 @@ import (
"github.com/ipfs/kubo/client/rpc"
apiv1 "github.com/onsonr/sonr/api/did/v1"
middleware "github.com/onsonr/sonr/x/did/middleware"
middleware "github.com/onsonr/sonr/x/did/context"
"github.com/onsonr/sonr/x/did/types"
)
@@ -90,7 +90,7 @@ func NewKeeper(
// IsClaimedServiceOrigin checks if a service origin is unclaimed
func (k Keeper) IsUnclaimedServiceOrigin(ctx sdk.Context, origin string) bool {
rec, _ := k.OrmDB.ServiceRecordTable().GetByOriginUri(ctx, origin)
rec, _ := k.OrmDB.ServiceRecordTable().GetByOrigin(ctx, origin)
return rec == nil
}
@@ -99,7 +99,7 @@ func (k Keeper) IsValidServiceOrigin(ctx sdk.Context, origin string, clientInfo
if origin != clientInfo.Hostname {
return false
}
rec, err := k.OrmDB.ServiceRecordTable().GetByOriginUri(ctx, origin)
rec, err := k.OrmDB.ServiceRecordTable().GetByOrigin(ctx, origin)
if err != nil {
return false
}
-12
View File
@@ -1,12 +0,0 @@
package keeper
import (
didv1 "github.com/onsonr/sonr/api/did/v1"
"github.com/onsonr/sonr/x/did/types"
)
func convertServiceRecord(rec *didv1.ServiceRecord) *types.Service {
return &types.Service{
Origin: rec.OriginUri,
}
}
+10 -40
View File
@@ -2,11 +2,6 @@ package keeper
import (
"context"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"google.golang.org/genproto/googleapis/api/httpbody"
"google.golang.org/grpc/peer"
"github.com/onsonr/sonr/x/did/types"
)
@@ -23,52 +18,27 @@ func NewQuerier(keeper Keeper) Querier {
// Params returns the total set of did parameters.
func (k Querier) Params(
c context.Context,
goCtx context.Context,
req *types.QueryRequest,
) (*types.QueryParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
p, err := k.Keeper.Params.Get(ctx)
if err != nil {
return nil, err
}
params := p.ActiveParams(k.HasIPFSConnection())
return &types.QueryParamsResponse{Params: &params}, nil
) (*types.QueryResponse, error) {
ctx := k.CurrentCtx(goCtx)
return &types.QueryResponse{Params: k.GetParams(ctx.SDK())}, nil
}
// Resolve implements types.QueryServer.
func (k Querier) Resolve(
goCtx context.Context,
req *types.QueryRequest,
) (*types.QueryResolveResponse, error) {
// ctx := sdk.UnwrapSDKContext(goCtx)
return &types.QueryResolveResponse{}, nil
) (*types.QueryResponse, error) {
ctx := k.CurrentCtx(goCtx)
return &types.QueryResponse{Params: k.GetParams(ctx.SDK())}, nil
}
// Service implements types.QueryServer.
func (k Querier) Service(
goCtx context.Context,
req *types.QueryRequest,
) (*types.QueryServiceResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
_, ok := peer.FromContext(goCtx)
if !ok {
return nil, fmt.Errorf("failed to get peer from context")
}
rec, err := k.OrmDB.ServiceRecordTable().GetByOriginUri(ctx, req.Origin)
if err != nil {
return nil, err
}
return &types.QueryServiceResponse{Service: convertServiceRecord(rec)}, nil
}
// HTMX implements types.QueryServer.
func (k Querier) HTMX(goCtx context.Context, req *types.QueryRequest) (*httpbody.HttpBody, error) {
// ctx := sdk.UnwrapSDKContext(goCtx)
return &httpbody.HttpBody{
ContentType: "text/html",
Data: []byte("<html><body>HTMX</body></html>"),
}, nil
) (*types.QueryResponse, error) {
ctx := k.CurrentCtx(goCtx)
return &types.QueryResponse{Service: ctx.GetServiceInfo(req.GetOrigin()), Params: ctx.Params()}, nil
}
+30 -38
View File
@@ -9,7 +9,7 @@ import (
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/onsonr/sonr/x/did/builder"
"github.com/onsonr/sonr/x/did/middleware"
snrctx "github.com/onsonr/sonr/x/did/context"
"github.com/onsonr/sonr/x/did/types"
)
@@ -24,38 +24,17 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer {
return &msgServer{k: keeper}
}
// UpdateParams updates the x/did module parameters.
func (ms msgServer) UpdateParams(
ctx context.Context,
msg *types.MsgUpdateParams,
) (*types.MsgUpdateParamsResponse, error) {
if ms.k.authority != msg.Authority {
// AuthorizeService implements types.MsgServer.
func (ms msgServer) AuthorizeService(goCtx context.Context, msg *types.MsgAuthorizeService) (*types.MsgAuthorizeServiceResponse, error) {
if ms.k.authority != msg.Controller {
return nil, errors.Wrapf(
govtypes.ErrInvalidSigner,
"invalid authority; expected %s, got %s",
ms.k.authority,
msg.Authority,
msg.Controller,
)
}
return nil, ms.k.Params.Set(ctx, msg.Params)
}
// Authorize implements types.MsgServer.
func (ms msgServer) Authorize(
ctx context.Context,
msg *types.MsgAuthorize,
) (*types.MsgAuthorizeResponse, error) {
if ms.k.authority != msg.Authority {
return nil, errors.Wrapf(
govtypes.ErrInvalidSigner,
"invalid authority; expected %s, got %s",
ms.k.authority,
msg.Authority,
)
}
// ctx := sdk.UnwrapSDKContext(goCtx)
return &types.MsgAuthorizeResponse{}, nil
return &types.MsgAuthorizeServiceResponse{}, nil
}
// AllocateVault implements types.MsgServer.
@@ -64,7 +43,7 @@ func (ms msgServer) AllocateVault(
msg *types.MsgAllocateVault,
) (*types.MsgAllocateVaultResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
clientInfo, err := middleware.ExtractClientInfo(goCtx)
clientInfo, err := snrctx.ExtractClientInfo(goCtx)
if err != nil {
return nil, err
}
@@ -79,7 +58,7 @@ func (ms msgServer) AllocateVault(
return nil, err
}
regOpts, err := builder.NewRegistrationOptions(msg.Origin, msg.Subject, cid, ms.k.GetParams(ctx))
regOpts, err := builder.GetPublicKeyCredentialCreationOptions(msg.Origin, msg.Subject, cid, ms.k.GetParams(ctx))
if err != nil {
return nil, err
}
@@ -113,23 +92,36 @@ func (ms msgServer) RegisterService(
) (*types.MsgRegisterServiceResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
clientInfo, err := middleware.ExtractClientInfo(goCtx)
clientInfo, err := snrctx.ExtractClientInfo(goCtx)
if err != nil {
return nil, err
}
// 1.Check if the service origin is valid
if !ms.k.IsValidServiceOrigin(ctx, msg.OriginUri, clientInfo) {
if !ms.k.IsValidServiceOrigin(ctx, msg.Service.Origin, clientInfo) {
return nil, types.ErrInvalidServiceOrigin
}
return ms.k.insertService(ctx, msg)
return ms.k.insertService(ctx, msg.Service)
}
// SyncVault implements types.MsgServer.
func (ms msgServer) SyncVault(
ctx context.Context,
msg *types.MsgSyncVault,
) (*types.MsgSyncVaultResponse, error) {
// SyncController implements types.MsgServer.
func (ms msgServer) SyncController(ctx context.Context, msg *types.MsgSyncController) (*types.MsgSyncControllerResponse, error) {
// ctx := sdk.UnwrapSDKContext(goCtx)
return &types.MsgSyncVaultResponse{}, nil
return &types.MsgSyncControllerResponse{}, nil
}
// UpdateParams updates the x/did module parameters.
func (ms msgServer) UpdateParams(
ctx context.Context,
msg *types.MsgUpdateParams,
) (*types.MsgUpdateParamsResponse, error) {
if ms.k.authority != msg.Authority {
return nil, errors.Wrapf(
govtypes.ErrInvalidSigner,
"invalid authority; expected %s, got %s",
ms.k.authority,
msg.Authority,
)
}
return nil, ms.k.Params.Set(ctx, msg.Params)
}
+4 -6
View File
@@ -3,19 +3,17 @@ package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
didv1 "github.com/onsonr/sonr/api/did/v1"
"github.com/onsonr/sonr/x/did/builder"
"github.com/onsonr/sonr/x/did/types"
)
// insertService inserts a service record into the database
func (k Keeper) insertService(
ctx sdk.Context,
svc *types.MsgRegisterService,
svc *types.Service,
) (*types.MsgRegisterServiceResponse, error) {
record := didv1.ServiceRecord{
Id: svc.OriginUri,
}
err := k.OrmDB.ServiceRecordTable().Insert(ctx, &record)
record := builder.APIFormatServiceRecord(svc)
err := k.OrmDB.ServiceRecordTable().Insert(ctx, record)
if err != nil {
return nil, err
}
+157
View File
@@ -1,12 +1,19 @@
package types
import (
"crypto/sha256"
"encoding/hex"
fmt "fmt"
"github.com/cosmos/btcutil/bech32"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
"github.com/mr-tron/base58/base58"
"github.com/onsonr/crypto"
// this line is used by starport scaffolding # 1
)
@@ -41,3 +48,153 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
type ChainCode uint32
const (
ChainCodeBTC ChainCode = 0
ChainCodeETH ChainCode = 60
ChainCodeIBC ChainCode = 118
ChainCodeSNR ChainCode = 703
)
var InitialChainCodes = map[DIDNamespace]ChainCode{
DIDNamespace_DID_NAMESPACE_BITCOIN: ChainCodeBTC,
DIDNamespace_DID_NAMESPACE_IBC: ChainCodeIBC,
DIDNamespace_DID_NAMESPACE_ETHEREUM: ChainCodeETH,
DIDNamespace_DID_NAMESPACE_SONR: ChainCodeSNR,
}
func (c ChainCode) FormatAddress(pubKey *PubKey) (string, error) {
switch c {
case ChainCodeBTC:
return bech32.Encode("bc", pubKey.Bytes())
case ChainCodeETH:
return bech32.Encode("eth", pubKey.Bytes())
case ChainCodeSNR:
return bech32.Encode("idx", pubKey.Bytes())
case ChainCodeIBC:
return bech32.Encode("cosmos", pubKey.Bytes())
}
return "", ErrUnsopportedChainCode
}
func (n DIDNamespace) ChainCode() (uint32, error) {
switch n {
case DIDNamespace_DID_NAMESPACE_BITCOIN:
return 0, nil
case DIDNamespace_DID_NAMESPACE_ETHEREUM:
return 64, nil
case DIDNamespace_DID_NAMESPACE_IBC:
return 118, nil
case DIDNamespace_DID_NAMESPACE_SONR:
return 703, nil
default:
return 0, fmt.Errorf("unsupported chain")
}
}
func (n DIDNamespace) DIDMethod() string {
switch n {
case DIDNamespace_DID_NAMESPACE_IPFS:
return "ipfs"
case DIDNamespace_DID_NAMESPACE_SONR:
return "sonr"
case DIDNamespace_DID_NAMESPACE_BITCOIN:
return "btcr"
case DIDNamespace_DID_NAMESPACE_ETHEREUM:
return "ethr"
case DIDNamespace_DID_NAMESPACE_IBC:
return "ibcr"
case DIDNamespace_DID_NAMESPACE_WEBAUTHN:
return "webauthn"
case DIDNamespace_DID_NAMESPACE_DWN:
return "motr"
case DIDNamespace_DID_NAMESPACE_SERVICE:
return "web"
default:
return "n/a"
}
}
func (n DIDNamespace) FormatDID(subject string) string {
return fmt.Sprintf("%s:%s", n.DIDMethod(), subject)
}
type EncodedKey []byte
func (e KeyEncoding) EncodeRaw(data []byte) (EncodedKey, error) {
switch e {
case KeyEncoding_KEY_ENCODING_RAW:
return data, nil
case KeyEncoding_KEY_ENCODING_HEX:
return []byte(hex.EncodeToString(data)), nil
case KeyEncoding_KEY_ENCODING_MULTIBASE:
return []byte(base58.Encode(data)), nil
default:
return nil, nil
}
}
func (e KeyEncoding) DecodeRaw(data EncodedKey) ([]byte, error) {
switch e {
case KeyEncoding_KEY_ENCODING_RAW:
return data, nil
case KeyEncoding_KEY_ENCODING_HEX:
return hex.DecodeString(string(data))
case KeyEncoding_KEY_ENCODING_MULTIBASE:
return base58.Decode(string(data))
default:
return nil, nil
}
}
type COSEAlgorithmIdentifier int
func (k KeyAlgorithm) CoseIdentifier() COSEAlgorithmIdentifier {
switch k {
case KeyAlgorithm_KEY_ALGORITHM_ES256:
return COSEAlgorithmIdentifier(-7)
case KeyAlgorithm_KEY_ALGORITHM_ES384:
return COSEAlgorithmIdentifier(-35)
case KeyAlgorithm_KEY_ALGORITHM_ES512:
return COSEAlgorithmIdentifier(-36)
case KeyAlgorithm_KEY_ALGORITHM_EDDSA:
return COSEAlgorithmIdentifier(-8)
case KeyAlgorithm_KEY_ALGORITHM_ES256K:
return COSEAlgorithmIdentifier(-10)
default:
return COSEAlgorithmIdentifier(0)
}
}
func (k KeyCurve) ComputePublicKey(data []byte) (*PubKey, error) {
return nil, ErrUnsupportedKeyCurve
}
func (k *Keyshare) Equals(o crypto.MPCShare) bool {
opk := o.GetPublicKey()
if opk != nil && k.PublicKey == nil {
return false
}
return k.GetRole() == o.GetRole()
}
func (k *Keyshare) IsUser() bool {
return k.Role == 2
}
func (k *Keyshare) IsValidator() bool {
return k.Role == 1
}
// ComputeOriginTXTRecord generates a fingerprint for a given origin
func ComputeOriginTXTRecord(origin string) string {
h := sha256.New()
h.Write([]byte(origin))
return fmt.Sprintf("v=sonr,o=%s,p=%x", origin, h.Sum(nil))
}
-136
View File
@@ -1,136 +0,0 @@
package types
import (
"encoding/hex"
fmt "fmt"
"github.com/cosmos/btcutil/bech32"
"github.com/mr-tron/base58/base58"
)
type ChainCode uint32
const (
ChainCodeBTC ChainCode = 0
ChainCodeETH ChainCode = 60
ChainCodeIBC ChainCode = 118
ChainCodeSNR ChainCode = 703
)
var InitialChainCodes = map[DIDNamespace]ChainCode{
DIDNamespace_DID_NAMESPACE_BITCOIN: ChainCodeBTC,
DIDNamespace_DID_NAMESPACE_IBC: ChainCodeIBC,
DIDNamespace_DID_NAMESPACE_ETHEREUM: ChainCodeETH,
DIDNamespace_DID_NAMESPACE_SONR: ChainCodeSNR,
}
func (c ChainCode) FormatAddress(pubKey *PubKey) (string, error) {
switch c {
case ChainCodeBTC:
return bech32.Encode("bc", pubKey.Bytes())
case ChainCodeETH:
return bech32.Encode("eth", pubKey.Bytes())
case ChainCodeSNR:
return bech32.Encode("idx", pubKey.Bytes())
case ChainCodeIBC:
return bech32.Encode("cosmos", pubKey.Bytes())
}
return "", ErrUnsopportedChainCode
}
func (n DIDNamespace) ChainCode() (uint32, error) {
switch n {
case DIDNamespace_DID_NAMESPACE_BITCOIN:
return 0, nil
case DIDNamespace_DID_NAMESPACE_ETHEREUM:
return 64, nil
case DIDNamespace_DID_NAMESPACE_IBC:
return 118, nil
case DIDNamespace_DID_NAMESPACE_SONR:
return 703, nil
default:
return 0, fmt.Errorf("unsupported chain")
}
}
func (n DIDNamespace) DIDMethod() string {
switch n {
case DIDNamespace_DID_NAMESPACE_IPFS:
return "ipfs"
case DIDNamespace_DID_NAMESPACE_SONR:
return "sonr"
case DIDNamespace_DID_NAMESPACE_BITCOIN:
return "btcr"
case DIDNamespace_DID_NAMESPACE_ETHEREUM:
return "ethr"
case DIDNamespace_DID_NAMESPACE_IBC:
return "ibcr"
case DIDNamespace_DID_NAMESPACE_WEBAUTHN:
return "webauthn"
case DIDNamespace_DID_NAMESPACE_DWN:
return "motr"
case DIDNamespace_DID_NAMESPACE_SERVICE:
return "web"
default:
return "n/a"
}
}
func (n DIDNamespace) FormatDID(subject string) string {
return fmt.Sprintf("%s:%s", n.DIDMethod(), subject)
}
type EncodedKey []byte
func (e KeyEncoding) EncodeRaw(data []byte) (EncodedKey, error) {
switch e {
case KeyEncoding_KEY_ENCODING_RAW:
return data, nil
case KeyEncoding_KEY_ENCODING_HEX:
return []byte(hex.EncodeToString(data)), nil
case KeyEncoding_KEY_ENCODING_MULTIBASE:
return []byte(base58.Encode(data)), nil
default:
return nil, nil
}
}
func (e KeyEncoding) DecodeRaw(data EncodedKey) ([]byte, error) {
switch e {
case KeyEncoding_KEY_ENCODING_RAW:
return data, nil
case KeyEncoding_KEY_ENCODING_HEX:
return hex.DecodeString(string(data))
case KeyEncoding_KEY_ENCODING_MULTIBASE:
return base58.Decode(string(data))
default:
return nil, nil
}
}
type COSEAlgorithmIdentifier int
func (k KeyAlgorithm) CoseIdentifier() COSEAlgorithmIdentifier {
switch k {
case KeyAlgorithm_KEY_ALGORITHM_ES256:
return COSEAlgorithmIdentifier(-7)
case KeyAlgorithm_KEY_ALGORITHM_ES384:
return COSEAlgorithmIdentifier(-35)
case KeyAlgorithm_KEY_ALGORITHM_ES512:
return COSEAlgorithmIdentifier(-36)
case KeyAlgorithm_KEY_ALGORITHM_EDDSA:
return COSEAlgorithmIdentifier(-8)
case KeyAlgorithm_KEY_ALGORITHM_ES256K:
return COSEAlgorithmIdentifier(-10)
default:
return COSEAlgorithmIdentifier(0)
}
}
func (k KeyCurve) ComputePublicKey(data []byte) (*PubKey, error) {
return nil, ErrUnsupportedKeyCurve
}
+2
View File
@@ -7,9 +7,11 @@ var (
ErrInvalidETHAddressFormat = sdkerrors.Register(ModuleName, 200, "invalid ETH address format")
ErrInvalidBTCAddressFormat = sdkerrors.Register(ModuleName, 201, "invalid BTC address format")
ErrInvalidIDXAddressFormat = sdkerrors.Register(ModuleName, 202, "invalid IDX address format")
ErrInvalidOriginFormat = sdkerrors.Register(ModuleName, 203, "invalid origin format")
ErrInvalidServiceOrigin = sdkerrors.Register(ModuleName, 300, "invalid service origin")
ErrUnrecognizedService = sdkerrors.Register(ModuleName, 301, "unrecognized service")
ErrUnsupportedKeyEncoding = sdkerrors.Register(ModuleName, 400, "unsupported key encoding")
ErrUnsopportedChainCode = sdkerrors.Register(ModuleName, 401, "unsupported chain code")
ErrUnsupportedKeyCurve = sdkerrors.Register(ModuleName, 402, "unsupported key curve")
ErrInvalidSignature = sdkerrors.Register(ModuleName, 403, "invalid signature")
)
+36 -16
View File
@@ -53,7 +53,6 @@ func DefaultParams() Params {
WhitelistedAssets: DefaultAssets(),
WhitelistedChains: DefaultChains(),
AllowedPublicKeys: DefaultKeyInfos(),
OpenidConfig: DefaultOpenIDConfig(),
LocalhostRegistrationEnabled: true,
ConveyancePreference: "direct",
AttestationFormats: []string{"packed", "android-key", "fido-u2f", "apple"},
@@ -163,21 +162,6 @@ func DefaultKeyInfos() []*KeyInfo {
}
}
func DefaultOpenIDConfig() *OpenIDConfig {
return &OpenIDConfig{
Issuer: "https://sonr.id",
AuthorizationEndpoint: "https://api.sonr.id/auth",
TokenEndpoint: "https://api.sonr.id/token",
UserinfoEndpoint: "https://api.sonr.id/userinfo",
ScopesSupported: []string{"openid", "profile", "email", "web3", "sonr"},
ResponseTypesSupported: []string{"code"},
ResponseModesSupported: []string{"query", "form_post"},
GrantTypesSupported: []string{"authorization_code", "refresh_token"},
AcrValuesSupported: []string{"passkey"},
SubjectTypesSupported: []string{"public"},
}
}
func (p Params) ActiveParams(ipfsActive bool) Params {
p.IpfsActive = ipfsActive
return p
@@ -198,3 +182,39 @@ func (p Params) Validate() error {
// TODO:
return nil
}
//
// # Genesis Structures
//
// Equal returns true if two asset infos are equal
func (a *AssetInfo) Equal(b *AssetInfo) bool {
if a == nil && b == nil {
return true
}
return false
}
// Equal returns true if two chain infos are equal
func (c *ChainInfo) Equal(b *ChainInfo) bool {
if c == nil && b == nil {
return true
}
return false
}
// Equal returns true if two key infos are equal
func (k *KeyInfo) Equal(b *KeyInfo) bool {
if k == nil && b == nil {
return true
}
return false
}
// Equal returns true if two validator infos are equal
func (v *ValidatorInfo) Equal(b *ValidatorInfo) bool {
if v == nil && b == nil {
return true
}
return false
}
+161 -861
View File
File diff suppressed because it is too large Load Diff
-137
View File
@@ -1,137 +0,0 @@
package types
import (
"encoding/hex"
"github.com/mr-tron/base58/base58"
)
//
// # Genesis Structures
//
// Equal returns true if two asset infos are equal
func (a *AssetInfo) Equal(b *AssetInfo) bool {
if a == nil && b == nil {
return true
}
return false
}
// Equal returns true if two chain infos are equal
func (c *ChainInfo) Equal(b *ChainInfo) bool {
if c == nil && b == nil {
return true
}
return false
}
// Equal returns true if two OpenID config infos are equal
func (o *OpenIDConfig) Equal(b *OpenIDConfig) bool {
if o == nil && b == nil {
return true
}
return false
}
// Equal returns true if two key infos are equal
func (k *KeyInfo) Equal(b *KeyInfo) bool {
if k == nil && b == nil {
return true
}
return false
}
// Equal returns true if two validator infos are equal
func (v *ValidatorInfo) Equal(b *ValidatorInfo) bool {
if v == nil && b == nil {
return true
}
return false
}
// DecodePublicKey extracts the public key from the given data
func (k *KeyInfo) DecodePublicKey(data interface{}) ([]byte, error) {
var bz []byte
switch v := data.(type) {
case string:
bz = []byte(v)
case []byte:
bz = v
default:
return nil, ErrUnsupportedKeyEncoding
}
if k.Encoding == KeyEncoding_KEY_ENCODING_RAW {
return bz, nil
}
if k.Encoding == KeyEncoding_KEY_ENCODING_HEX {
return hex.DecodeString(string(bz))
}
if k.Encoding == KeyEncoding_KEY_ENCODING_MULTIBASE {
return base58.Decode(string(bz))
}
return nil, ErrUnsupportedKeyEncoding
}
// EncodePublicKey encodes the public key according to the KeyInfo's encoding
func (k *KeyInfo) EncodePublicKey(data []byte) (string, error) {
if k.Encoding == KeyEncoding_KEY_ENCODING_RAW {
return string(data), nil
}
if k.Encoding == KeyEncoding_KEY_ENCODING_HEX {
return hex.EncodeToString(data), nil
}
if k.Encoding == KeyEncoding_KEY_ENCODING_MULTIBASE {
return base58.Encode(data), nil
}
return "", ErrUnsupportedKeyEncoding
}
// DiscoveryDocument represents the OIDC discovery document.
type DiscoveryDocument struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
UserinfoEndpoint string `json:"userinfo_endpoint"`
JwksURI string `json:"jwks_uri"`
RegistrationEndpoint string `json:"registration_endpoint"`
ScopesSupported []string `json:"scopes_supported"`
ResponseTypesSupported []string `json:"response_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
ClaimsSupported []string `json:"claims_supported"`
GrantTypesSupported []string `json:"grant_types_supported"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
}
var WalletKeyInfo = &KeyInfo{
Role: KeyRole_KEY_ROLE_DELEGATION,
Curve: KeyCurve_KEY_CURVE_SECP256K1,
Algorithm: KeyAlgorithm_KEY_ALGORITHM_ECDSA,
Encoding: KeyEncoding_KEY_ENCODING_HEX,
Type: KeyType_KEY_TYPE_BIP32,
}
var EthKeyInfo = &KeyInfo{
Role: KeyRole_KEY_ROLE_DELEGATION,
Curve: KeyCurve_KEY_CURVE_KECCAK256,
Algorithm: KeyAlgorithm_KEY_ALGORITHM_ECDSA,
Encoding: KeyEncoding_KEY_ENCODING_HEX,
Type: KeyType_KEY_TYPE_BIP32,
}
var SonrKeyInfo = &KeyInfo{
Role: KeyRole_KEY_ROLE_INVOCATION,
Curve: KeyCurve_KEY_CURVE_P256,
Algorithm: KeyAlgorithm_KEY_ALGORITHM_ECDSA,
Encoding: KeyEncoding_KEY_ENCODING_HEX,
Type: KeyType_KEY_TYPE_MPC,
}
var ChainCodeKeyInfos = map[ChainCode]*KeyInfo{
ChainCodeBTC: WalletKeyInfo,
ChainCodeETH: EthKeyInfo,
ChainCodeSNR: SonrKeyInfo,
ChainCodeIBC: WalletKeyInfo,
}
+2135 -2682
View File
File diff suppressed because it is too large Load Diff
+68 -41
View File
@@ -1,15 +1,44 @@
package types
import (
fmt "fmt"
"math/big"
"encoding/hex"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/onsonr/crypto/core/curves"
"github.com/onsonr/crypto/signatures/ecdsa"
"golang.org/x/crypto/sha3"
"github.com/mr-tron/base58/base58"
"github.com/onsonr/crypto"
)
var WalletKeyInfo = &KeyInfo{
Role: KeyRole_KEY_ROLE_DELEGATION,
Curve: KeyCurve_KEY_CURVE_SECP256K1,
Algorithm: KeyAlgorithm_KEY_ALGORITHM_ECDSA,
Encoding: KeyEncoding_KEY_ENCODING_HEX,
Type: KeyType_KEY_TYPE_BIP32,
}
var EthKeyInfo = &KeyInfo{
Role: KeyRole_KEY_ROLE_DELEGATION,
Curve: KeyCurve_KEY_CURVE_KECCAK256,
Algorithm: KeyAlgorithm_KEY_ALGORITHM_ECDSA,
Encoding: KeyEncoding_KEY_ENCODING_HEX,
Type: KeyType_KEY_TYPE_BIP32,
}
var SonrKeyInfo = &KeyInfo{
Role: KeyRole_KEY_ROLE_INVOCATION,
Curve: KeyCurve_KEY_CURVE_P256,
Algorithm: KeyAlgorithm_KEY_ALGORITHM_ECDSA,
Encoding: KeyEncoding_KEY_ENCODING_HEX,
Type: KeyType_KEY_TYPE_MPC,
}
var ChainCodeKeyInfos = map[ChainCode]*KeyInfo{
ChainCodeBTC: WalletKeyInfo,
ChainCodeETH: EthKeyInfo,
ChainCodeSNR: SonrKeyInfo,
ChainCodeIBC: WalletKeyInfo,
}
// NewEthPublicKey returns a new ethereum public key
func NewPublicKey(data []byte, keyInfo *KeyInfo) (*PubKey, error) {
encKey, err := keyInfo.Encoding.EncodeRaw(data)
@@ -52,21 +81,12 @@ func (k *PubKey) Clone() cryptotypes.PubKey {
// VerifySignature verifies a signature over the given message
func (k *PubKey) VerifySignature(msg []byte, sig []byte) bool {
pp, err := buildEcPoint(k.Bytes())
pk, err := crypto.ComputeEcdsaPublicKey(k.Bytes())
sigMpc, err := crypto.DeserializeMPCSignature(sig)
if err != nil {
return false
}
sigEd, err := ecdsa.DeserializeSecp256k1Signature(sig)
if err != nil {
return false
}
hash := sha3.New256()
_, err = hash.Write(msg)
if err != nil {
return false
}
digest := hash.Sum(nil)
return curves.VerifyEcdsa(pp, digest[:], sigEd)
return crypto.VerifyMPCSignature(sigMpc, msg, pk)
}
// Equals returns true if two public keys are equal
@@ -79,36 +99,43 @@ func (k *PubKey) Equals(k2 cryptotypes.PubKey) bool {
// Type returns the type of the public key
func (k *PubKey) Type() string {
return ""
return k.KeyType.String()
}
// VerifySignature verifies the signature of a message
func VerifySignature(key []byte, msg []byte, sig []byte) bool {
pp, err := buildEcPoint(key)
if err != nil {
return false
// DecodePublicKey extracts the public key from the given data
func (k *KeyInfo) DecodePublicKey(data interface{}) ([]byte, error) {
var bz []byte
switch v := data.(type) {
case string:
bz = []byte(v)
case []byte:
bz = v
default:
return nil, ErrUnsupportedKeyEncoding
}
sigEd, err := ecdsa.DeserializeSecp256k1Signature(sig)
if err != nil {
return false
if k.Encoding == KeyEncoding_KEY_ENCODING_RAW {
return bz, nil
}
hash := sha3.New256()
_, err = hash.Write(msg)
if err != nil {
return false
if k.Encoding == KeyEncoding_KEY_ENCODING_HEX {
return hex.DecodeString(string(bz))
}
digest := hash.Sum(nil)
return curves.VerifyEcdsa(pp, digest[:], sigEd)
if k.Encoding == KeyEncoding_KEY_ENCODING_MULTIBASE {
return base58.Decode(string(bz))
}
return nil, ErrUnsupportedKeyEncoding
}
// BuildEcPoint builds an elliptic curve point from a compressed byte slice
func buildEcPoint(pubKey []byte) (*curves.EcPoint, error) {
crv := curves.K256()
x := new(big.Int).SetBytes(pubKey[1:33])
y := new(big.Int).SetBytes(pubKey[33:])
ecCurve, err := crv.ToEllipticCurve()
if err != nil {
return nil, fmt.Errorf("error converting curve: %v", err)
// EncodePublicKey encodes the public key according to the KeyInfo's encoding
func (k *KeyInfo) EncodePublicKey(data []byte) (string, error) {
if k.Encoding == KeyEncoding_KEY_ENCODING_RAW {
return string(data), nil
}
return &curves.EcPoint{X: x, Y: y, Curve: ecCurve}, nil
if k.Encoding == KeyEncoding_KEY_ENCODING_HEX {
return hex.EncodeToString(data), nil
}
if k.Encoding == KeyEncoding_KEY_ENCODING_MULTIBASE {
return base58.Encode(data), nil
}
return "", ErrUnsupportedKeyEncoding
}
+72 -1597
View File
File diff suppressed because it is too large Load Diff
-28
View File
@@ -1,28 +0,0 @@
package types
import didv1 "github.com/onsonr/sonr/api/did/v1"
func (m *MsgRegisterService) ExtractServiceRecord() (*didv1.ServiceRecord, error) {
return &didv1.ServiceRecord{
Controller: m.Controller,
OriginUri: m.OriginUri,
Description: m.Description,
Permissions: convertPermissions(m.GetScopes()),
}, nil
}
func convertPermissions(permissions *Permissions) *didv1.Permissions {
if permissions == nil {
return nil
}
return &didv1.Permissions{}
}
// UserInfo represents the user information.
type UserInfo struct {
DID string `json:"did"`
Sub string `json:"sub"`
Name string `json:"name"`
Email string `json:"email"`
// Add other claims as needed
}
-12
View File
@@ -1,12 +0,0 @@
package types
// ByteArray is a list of byte arrays
type ByteArray = [][]byte
// ToVerificationMethod converts a Profile to a VerificationMethod
func (p Profile) ToVerificationMethod() VerificationMethod {
return VerificationMethod{
Id: p.Id,
Controller: p.Controller,
}
}
+736 -957
View File
File diff suppressed because it is too large Load Diff
+346 -752
View File
File diff suppressed because it is too large Load Diff
-66
View File
@@ -1,66 +0,0 @@
package types
import (
"crypto/hmac"
"crypto/sha512"
"encoding/binary"
"errors"
"math/big"
"github.com/btcsuite/btcd/btcec/v2"
)
// ComputeAccountPublicKey computes the public key of a child key given the extended public key, chain code, and index.
func ComputeAccountPublicKey(extPubKey []byte, chainCode uint32, index int) ([]byte, error) {
// Check if the index is a hardened child key
if chainCode&0x80000000 != 0 && index < 0 {
return nil, errors.New("invalid index")
}
// Serialize the public key
pubKey, err := btcec.ParsePubKey(extPubKey)
if err != nil {
return nil, err
}
pubKeyBytes := pubKey.SerializeCompressed()
// Serialize the index
indexBytes := make([]byte, 4)
binary.BigEndian.PutUint32(indexBytes, uint32(index))
// Compute the HMAC-SHA512
mac := hmac.New(sha512.New, []byte{byte(chainCode)})
mac.Write(pubKeyBytes)
mac.Write(indexBytes)
I := mac.Sum(nil)
// Split I into two 32-byte sequences
IL := I[:32]
// Convert IL to a big integer
ilNum := new(big.Int).SetBytes(IL)
// Check if parse256(IL) >= n
curve := btcec.S256()
if ilNum.Cmp(curve.N) >= 0 {
return nil, errors.New("invalid child key")
}
// Compute the child public key
ilx, ily := curve.ScalarBaseMult(IL)
childX, childY := curve.Add(ilx, ily, pubKey.X(), pubKey.Y())
lx := newBigIntFieldVal(childX)
ly := newBigIntFieldVal(childY)
// Create the child public key
childPubKey := btcec.NewPublicKey(lx, ly)
childPubKeyBytes := childPubKey.SerializeCompressed()
return childPubKeyBytes, nil
}
// newBigIntFieldVal creates a new field value from a big integer.
func newBigIntFieldVal(val *big.Int) *btcec.FieldVal {
lx := new(btcec.FieldVal)
lx.SetByteSlice(val.Bytes())
return lx
}
+44 -31
View File
@@ -7,12 +7,18 @@ import (
"github.com/onsonr/crypto/core/curves"
)
// Accumulator is the accumulator for the ZKP
type Accumulator []byte
// Element is the element for the BLS scheme
type Element = accumulator.Element
// NewProperty creates a new Property which is used for ZKP
func NewProperty(propertyKey string, pubKey []byte) (*Property, error) {
input := append(pubKey, []byte(propertyKey)...)
// Witness is the witness for the ZKP
type Witness []byte
// NewProof creates a new Proof which is used for ZKP
func NewProof(id, controller, issuer, property string, pubKey []byte) (*Proof, error) {
input := append(pubKey, []byte(property)...)
hash := []byte(input)
curve := curves.BLS12381(&curves.PointBls12381G1{})
@@ -26,47 +32,54 @@ func NewProperty(propertyKey string, pubKey []byte) (*Property, error) {
return nil, fmt.Errorf("failed to marshal secret key: %w", err)
}
return &Property{Key: keyBytes}, nil
return &Proof{
Id: id,
Controller: controller,
Issuer: issuer,
Property: property,
Accumulator: keyBytes,
}, nil
}
// CreateAccumulator creates a new accumulator
func CreateAccumulator(prop *Property, values ...string) (*Accumulator, error) {
// CreateAccumulator creates a new accumulator for a Proof
func CreateAccumulator(proof *Proof, values ...string) error {
curve := curves.BLS12381(&curves.PointBls12381G1{})
acc, err := new(accumulator.Accumulator).New(curve)
if err != nil {
return nil, err
return err
}
secretKey := new(accumulator.SecretKey)
if err := secretKey.UnmarshalBinary(prop.Key); err != nil {
return nil, err
if err := secretKey.UnmarshalBinary(proof.Accumulator); err != nil {
return err
}
fin, _, err := acc.Update(secretKey, ConvertValuesToZeroKnowledgeElements(values), nil)
if err != nil {
return nil, err
return err
}
accBytes, err := fin.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("failed to marshal accumulator: %w", err)
return fmt.Errorf("failed to marshal accumulator: %w", err)
}
return &Accumulator{Accumulator: accBytes}, nil
proof.Accumulator = accBytes
return nil
}
// CreateWitness creates a witness for the accumulator for a given value
func CreateWitness(prop *Property, acc *Accumulator, value string) (*Witness, error) {
// CreateWitness creates a witness for the accumulator in a Proof for a given value
func CreateWitness(proof *Proof, value string) ([]byte, error) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
element := curve.Scalar.Hash([]byte(value))
secretKey := new(accumulator.SecretKey)
if err := secretKey.UnmarshalBinary(prop.Key); err != nil {
if err := secretKey.UnmarshalBinary(proof.Accumulator); err != nil {
return nil, err
}
accObj := new(accumulator.Accumulator)
if err := accObj.UnmarshalBinary(acc.Accumulator); err != nil {
if err := accObj.UnmarshalBinary(proof.Accumulator); err != nil {
return nil, fmt.Errorf("failed to unmarshal accumulator: %w", err)
}
@@ -79,14 +92,13 @@ func CreateWitness(prop *Property, acc *Accumulator, value string) (*Witness, er
if err != nil {
return nil, fmt.Errorf("failed to marshal witness: %w", err)
}
return &Witness{Witness: witnessBytes}, nil
return witnessBytes, nil
}
// VerifyWitness proves that a value is a member of the accumulator
func VerifyWitness(prop *Property, acc *Accumulator, witness *Witness) error {
func VerifyWitness(proof *Proof, acc Accumulator, witness Witness) error {
secretKey := new(accumulator.SecretKey)
if err := secretKey.UnmarshalBinary(prop.Key); err != nil {
if err := secretKey.UnmarshalBinary([]byte(proof.Id)); err != nil {
return err
}
@@ -97,41 +109,42 @@ func VerifyWitness(prop *Property, acc *Accumulator, witness *Witness) error {
}
accObj := new(accumulator.Accumulator)
if err := accObj.UnmarshalBinary(acc.Accumulator); err != nil {
if err := accObj.UnmarshalBinary(proof.Accumulator); err != nil {
return fmt.Errorf("failed to unmarshal accumulator: %w", err)
}
witnessObj := new(accumulator.MembershipWitness)
if err := witnessObj.UnmarshalBinary(witness.Witness); err != nil {
if err := witnessObj.UnmarshalBinary(witness); err != nil {
return fmt.Errorf("failed to unmarshal witness: %w", err)
}
return witnessObj.Verify(publicKey, accObj)
}
// UpdateAccumulator updates the accumulator with new values
func UpdateAccumulator(prop *Property, acc *Accumulator, addValues []string, removeValues []string) (*Accumulator, error) {
// UpdateAccumulator updates the accumulator in a Proof with new values
func UpdateAccumulator(proof *Proof, addValues []string, removeValues []string) error {
secretKey := new(accumulator.SecretKey)
if err := secretKey.UnmarshalBinary(prop.Key); err != nil {
return nil, err
if err := secretKey.UnmarshalBinary(proof.Accumulator); err != nil {
return err
}
accObj := new(accumulator.Accumulator)
if err := accObj.UnmarshalBinary(acc.Accumulator); err != nil {
return nil, fmt.Errorf("failed to unmarshal accumulator: %w", err)
if err := accObj.UnmarshalBinary(proof.Accumulator); err != nil {
return fmt.Errorf("failed to unmarshal accumulator: %w", err)
}
updatedAcc, _, err := accObj.Update(secretKey, ConvertValuesToZeroKnowledgeElements(addValues), ConvertValuesToZeroKnowledgeElements(removeValues))
if err != nil {
return nil, err
return err
}
updatedAccBytes, err := updatedAcc.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("failed to marshal updated accumulator: %w", err)
return fmt.Errorf("failed to marshal updated accumulator: %w", err)
}
return &Accumulator{Accumulator: updatedAccBytes}, nil
proof.Accumulator = updatedAccBytes
return nil
}
// ConvertValuesToZeroKnowledgeElements converts a slice of strings to a slice of accumulator elements