feature/1114 implement account interface (#1167)

- **refactor: move session-related code to middleware package**
- **refactor: update PKL build process and adjust related
configurations**
- **feat: integrate base.cosmos.v1 Genesis module**
- **refactor: pass session context to modal rendering functions**
- **refactor: move nebula package to app directory and update templ
version**
- **refactor: Move home section video view to dedicated directory**
- **refactor: remove unused views file**
- **refactor: move styles and UI components to global scope**
- **refactor: Rename images.go to cdn.go**
- **feat: Add Empty State Illustrations**
- **refactor: Consolidate Vault Index Logic**
- **fix: References to App.wasm and remove Vault Directory embedded CDN
files**
- **refactor: Move CDN types to Models**
- **fix: Correct line numbers in templ error messages for
arch_templ.go**
- **refactor: use common types for peer roles**
- **refactor: move common types and ORM to a shared package**
- **fix: Config import dwn**
- **refactor: move nebula directory to app**
- **feat: Rebuild nebula**
- **fix: correct file paths in panels templates**
- **feat: Remove duplicate types**
- **refactor: Move dwn to pkg/core**
- **refactor: Binary Structure**
- **feat: Introduce Crypto Pkg**
- **fix: Broken Process Start**
- **feat: Update pkg/* structure**
- **feat: Refactor PKL Structure**
- **build: update pkl build process**
- **chore: Remove Empty Files**
- **refactor: remove unused macaroon package**
- **feat: Add WebAwesome Components**
- **refactor: consolidate build and generation tasks into a single
taskfile, remove redundant makefile targets**
- **refactor: refactor server and move components to pkg/core/dwn**
- **build: update go modules**
- **refactor: move gateway logic into dedicated hway command**
- **feat: Add KSS (Krawczyk-Song-Song) MPC cryptography module**
- **feat: Implement MPC-based JWT signing and UCAN token generation**
- **feat: add support for MPC-based JWT signing**
- **feat: Implement MPC-based UCAN capabilities for smart accounts**
- **feat: add address field to keyshareSource**
- **feat: Add comprehensive MPC test suite for keyshares, UCAN tokens,
and token attenuations**
- **refactor: improve MPC keyshare management and signing process**
- **feat: enhance MPC capability hierarchy documentation**
- **refactor: rename GenerateKeyshares function to NewKeyshareSource for
clarity**
- **refactor: remove unused Ethereum address computation**
- **feat: Add HasHandle and IsAuthenticated methods to HTTPContext**
- **refactor: Add context.Context support to session HTTPContext**
- **refactor: Resolve context interface conflicts in HTTPContext**
- **feat: Add session ID context key and helper functions**
- **feat: Update WebApp Page Rendering**
- **refactor: Simplify context management by using single HTTPContext
key**
- **refactor: Simplify HTTPContext creation and context management in
session middleware**
- **refactor: refactor session middleware to use a single data
structure**
- **refactor: Simplify HTTPContext implementation and session data
handling**
- **refactor: Improve session context handling and prevent nil pointer
errors**
- **refactor: Improve session context handling with nil safety and type
support**
- **refactor: improve session data injection**
- **feat: add full-screen modal component and update registration flow**
- **chore: add .air.toml to .gitignore**
- **feat: add Air to devbox and update dependencies**
This commit is contained in:
Prad Nukala
2024-11-23 01:28:58 -05:00
committed by GitHub
parent bf94277b0f
commit 89989fa102
549 changed files with 74162 additions and 9856 deletions
+117
View File
@@ -0,0 +1,117 @@
package mpc
import (
"fmt"
"github.com/ucan-wg/go-ucan"
)
// Capability hierarchy for smart account operations
// ----------------------------------------------
// OWNER
// └─ OPERATOR
// ├─ EXECUTE
// ├─ PROPOSE
// └─ SIGN
// └─ SET_POLICY
// └─ SET_THRESHOLD
// └─ RECOVER
// └─ SOCIAL
// Define capability hierarchy for smart account operations
const (
// Root capabilities
CAP_OWNER = "OWNER" // Full account control
CAP_OPERATOR = "OPERATOR" // Can perform operations
CAP_OBSERVER = "OBSERVER" // Can view account state
// Operation capabilities
CAP_EXECUTE = "EXECUTE" // Can execute transactions
CAP_PROPOSE = "PROPOSE" // Can propose transactions
CAP_SIGN = "SIGN" // Can sign transactions
// Policy capabilities
CAP_SET_POLICY = "SET_POLICY" // Can modify account policies
CAP_SET_THRESHOLD = "SET_THRESHOLD" // Can modify signing threshold
// Recovery capabilities
CAP_RECOVER = "RECOVER" // Can initiate recovery
CAP_SOCIAL = "SOCIAL" // Can act as social recovery
)
// SmartAccountCapabilities defines the capability hierarchy
func NewSmartAccountCapabilities() ucan.NestedCapabilities {
return ucan.NewNestedCapabilities(
CAP_OWNER,
CAP_OPERATOR,
CAP_OBSERVER,
CAP_EXECUTE,
CAP_PROPOSE,
CAP_SIGN,
CAP_SET_POLICY,
CAP_SET_THRESHOLD,
CAP_RECOVER,
CAP_SOCIAL,
)
}
// Resource types for smart account operations
type ResourceType string
const (
RES_ACCOUNT = "account"
RES_TRANSACTION = "tx"
RES_POLICY = "policy"
RES_RECOVERY = "recovery"
)
// NewSmartAccountResource creates a new resource identifier
func NewSmartAccountResource(resType ResourceType, path string) ucan.Resource {
return ucan.NewStringLengthResource(string(resType), path)
}
// CreateSmartAccountAttenuations creates default attenuations for a smart account
func CreateSmartAccountAttenuations(
caps ucan.NestedCapabilities,
accountAddr string,
) ucan.Attenuations {
return ucan.Attenuations{
// Owner capabilities
{caps.Cap(CAP_OWNER), NewSmartAccountResource(RES_ACCOUNT, accountAddr)},
// Operation capabilities
{caps.Cap(CAP_EXECUTE), NewSmartAccountResource(RES_TRANSACTION, fmt.Sprintf("%s:*", accountAddr))},
{caps.Cap(CAP_PROPOSE), NewSmartAccountResource(RES_TRANSACTION, fmt.Sprintf("%s:*", accountAddr))},
{caps.Cap(CAP_SIGN), NewSmartAccountResource(RES_TRANSACTION, fmt.Sprintf("%s:*", accountAddr))},
// Policy capabilities
{caps.Cap(CAP_SET_POLICY), NewSmartAccountResource(RES_POLICY, fmt.Sprintf("%s:*", accountAddr))},
{caps.Cap(CAP_SET_THRESHOLD), NewSmartAccountResource(RES_POLICY, fmt.Sprintf("%s:threshold", accountAddr))},
}
}
// Policy represents smart account execution policies
type PolicyType string
const (
POLICY_THRESHOLD = "threshold"
POLICY_TIMELOCK = "timelock"
POLICY_WHITELIST = "whitelist"
)
// CreatePolicyAttenuation creates attenuations for policy management
func CreatePolicyAttenuation(
caps ucan.NestedCapabilities,
accountAddr string,
policyType PolicyType,
) ucan.Attenuations {
return ucan.Attenuations{
{
caps.Cap(CAP_SET_POLICY),
NewSmartAccountResource(
RES_POLICY,
fmt.Sprintf("%s:%s", accountAddr, policyType),
),
},
}
}
+97
View File
@@ -0,0 +1,97 @@
package mpc
import (
"crypto/sha256"
"encoding/base64"
"fmt"
"github.com/golang-jwt/jwt"
)
// MPCSigningMethod implements the SigningMethod interface for MPC-based signing
type MPCSigningMethod struct {
Name string
ks keyshareSource
}
// newMPCSigningMethod creates a new MPC signing method with the given keyshare source
func newMPCSigningMethod(name string, ks keyshareSource) *MPCSigningMethod {
return &MPCSigningMethod{
Name: name,
ks: ks,
}
}
// Alg returns the signing method's name
func (m *MPCSigningMethod) Alg() string {
return m.Name
}
// Verify verifies the signature using the MPC public key
func (m *MPCSigningMethod) Verify(signingString, signature string, key interface{}) error {
// Decode the signature
sig, err := base64.RawURLEncoding.DecodeString(signature)
if err != nil {
return err
}
// Hash the signing string
hasher := sha256.New()
hasher.Write([]byte(signingString))
digest := hasher.Sum(nil)
// Verify using the keyshare's public key
valid, err := VerifySignature(m.ks.valShare.PublicKey, digest, sig)
if err != nil {
return fmt.Errorf("failed to verify signature: %w", err)
}
if !valid {
return fmt.Errorf("invalid signature")
}
return nil
}
// Sign signs the data using MPC
func (m *MPCSigningMethod) Sign(signingString string, key interface{}) (string, error) {
// Hash the signing string
hasher := sha256.New()
hasher.Write([]byte(signingString))
digest := hasher.Sum(nil)
// Create signing functions
signFunc, err := m.ks.userShare.SignFunc(digest)
if err != nil {
return "", fmt.Errorf("failed to create sign function: %w", err)
}
valSignFunc, err := m.ks.valShare.SignFunc(digest)
if err != nil {
return "", fmt.Errorf("failed to create validator sign function: %w", err)
}
// Run the signing protocol
sig, err := RunSignProtocol(valSignFunc, signFunc)
if err != nil {
return "", fmt.Errorf("failed to run sign protocol: %w", err)
}
// Serialize the signature
sigBytes, err := SerializeSignature(sig)
if err != nil {
return "", fmt.Errorf("failed to serialize signature: %w", err)
}
// Encode the signature
encoded := base64.RawURLEncoding.EncodeToString(sigBytes)
return encoded, nil
}
func init() {
// Register the MPC signing method
jwt.RegisterSigningMethod("MPC256", func() jwt.SigningMethod {
return &MPCSigningMethod{
Name: "MPC256",
}
})
}
+107
View File
@@ -0,0 +1,107 @@
package mpc
import (
"crypto/ecdsa"
"errors"
"math/big"
"github.com/onsonr/sonr/pkg/crypto/core/curves"
"github.com/onsonr/sonr/pkg/crypto/core/protocol"
"github.com/onsonr/sonr/pkg/crypto/tecdsa/dklsv1"
)
// NewKeyshareSource generates a new MPC keyshare
func NewKeyshareSource() (KeyshareSource, error) {
curve := curves.K256()
valKs := dklsv1.NewAliceDkg(curve, protocol.Version1)
userKs := dklsv1.NewBobDkg(curve, protocol.Version1)
aErr, bErr := runIteratedProtocol(userKs, valKs)
if err := checkIteratedErrors(aErr, bErr); err != nil {
return nil, err
}
valRes, err := valKs.Result(protocol.Version1)
if err != nil {
return nil, err
}
valShare, err := NewValKeyshare(valRes)
if err != nil {
return nil, err
}
userRes, err := userKs.Result(protocol.Version1)
if err != nil {
return nil, err
}
userShare, err := NewUserKeyshare(userRes)
if err != nil {
return nil, err
}
return createKeyshareSource(valShare, userShare)
}
// RunSignProtocol runs the MPC signing protocol
func RunSignProtocol(signFuncVal SignFunc, signFuncUser SignFunc) (Signature, error) {
aErr, bErr := runIteratedProtocol(signFuncVal, signFuncUser)
if err := checkIteratedErrors(aErr, bErr); err != nil {
return nil, err
}
out, err := signFuncUser.Result(protocol.Version1)
if err != nil {
return nil, err
}
return dklsv1.DecodeSignature(out)
}
// RunRefreshProtocol runs the MPC refresh protocol
func RunRefreshProtocol(refreshFuncVal RefreshFunc, refreshFuncUser RefreshFunc) (KeyshareSource, error) {
aErr, bErr := runIteratedProtocol(refreshFuncVal, refreshFuncUser)
if err := checkIteratedErrors(aErr, bErr); err != nil {
return nil, err
}
valRefreshResult, err := refreshFuncVal.Result(protocol.Version1)
if err != nil {
return nil, err
}
valShare, err := NewValKeyshare(valRefreshResult)
if err != nil {
return nil, err
}
userRefreshResult, err := refreshFuncUser.Result(protocol.Version1)
if err != nil {
return nil, err
}
userShare, err := NewUserKeyshare(userRefreshResult)
if err != nil {
return nil, err
}
return createKeyshareSource(valShare, userShare)
}
// SerializeSecp256k1Signature serializes an ECDSA signature into a byte slice
func SerializeSignature(sig Signature) ([]byte, error) {
rBytes := sig.R.Bytes()
sBytes := sig.S.Bytes()
sigBytes := make([]byte, 66) // V (1 byte) + R (32 bytes) + S (32 bytes)
sigBytes[0] = byte(sig.V)
copy(sigBytes[33-len(rBytes):33], rBytes)
copy(sigBytes[66-len(sBytes):66], sBytes)
return sigBytes, nil
}
// DeserializeSecp256k1Signature deserializes an ECDSA signature from a byte slice
func DeserializeSignature(sigBytes []byte) (Signature, error) {
if len(sigBytes) != 66 {
return nil, errors.New("malformed signature: not the correct size")
}
sig := &curves.EcdsaSignature{
V: int(sigBytes[0]),
R: new(big.Int).SetBytes(sigBytes[1:33]),
S: new(big.Int).SetBytes(sigBytes[33:66]),
}
return sig, nil
}
// VerifyMPCSignature verifies an MPC signature
func VerifyMPCSignature(sig Signature, msg []byte, publicKey *ecdsa.PublicKey) bool {
return ecdsa.Verify(publicKey, msg, sig.R, sig.S)
}
+35
View File
@@ -0,0 +1,35 @@
package mpc_test
import (
"fmt"
"testing"
"github.com/onsonr/sonr/pkg/crypto/mpc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestKeyshareGeneration(t *testing.T) {
// Test data
testData := []byte("hello world")
// Generate keyshares
src, err := mpc.NewKeyshareSource()
require.NoError(t, err)
src.Address()
// Test signing with keyshares
sig, err := src.SignData(testData)
require.NoError(t, err)
require.NotNil(t, sig)
// Verify signature
valid, err := src.VerifyData(testData, sig)
require.NoError(t, err)
assert.True(t, valid)
tk, err := src.DefaultOriginToken()
require.NoError(t, err)
cid, err := tk.CID()
require.NoError(t, err)
fmt.Println(cid)
}
+198
View File
@@ -0,0 +1,198 @@
package mpc
import (
"crypto/ecdsa"
"encoding/json"
"errors"
"github.com/onsonr/sonr/pkg/crypto/core/curves"
"github.com/onsonr/sonr/pkg/crypto/core/protocol"
"github.com/onsonr/sonr/pkg/crypto/tecdsa/dklsv1"
"golang.org/x/crypto/sha3"
)
var ErrInvalidKeyshareRole = errors.New("invalid keyshare role")
type Role int
const (
RoleUnknown Role = iota
RoleUser
RoleValidator
)
func (r Role) IsUser() bool {
return r == RoleUser
}
func (r Role) IsValidator() bool {
return r == RoleValidator
}
// Message is the protocol.Message that is used for MPC
type Message *protocol.Message
type PublicKey *ecdsa.PublicKey
type Signature *curves.EcdsaSignature
// RefreshFunc is the type for the refresh function
type RefreshFunc interface {
protocol.Iterator
}
// SignFunc is the type for the sign function
type SignFunc interface {
protocol.Iterator
}
type ValKeyshare struct {
Message Message `json:"message"`
Role int `json:"role"` // 1 for validator, 2 for user
PublicKey []byte `json:"public-key"`
}
func NewValKeyshare(msg Message) (*ValKeyshare, error) {
valShare, err := dklsv1.DecodeAliceDkgResult(msg)
if err != nil {
return nil, err
}
return &ValKeyshare{
Message: msg,
Role: 1,
PublicKey: valShare.PublicKey.ToAffineUncompressed(),
}, nil
}
func (v ValKeyshare) GetPayloads() map[string][]byte {
return v.Message.Payloads
}
func (v ValKeyshare) GetMetadata() map[string]string {
return v.Message.Metadata
}
func (v ValKeyshare) GetPublicKey() []byte {
return v.PublicKey
}
func (v ValKeyshare) GetProtocol() string {
return v.Message.Protocol
}
func (v ValKeyshare) GetRole() int32 {
return int32(v.Role)
}
func (v ValKeyshare) GetVersion() uint32 {
return uint32(v.Message.Version)
}
func (k ValKeyshare) ECDSAPublicKey() (*ecdsa.PublicKey, error) {
return ComputeEcdsaPublicKey(k.PublicKey)
}
func (k ValKeyshare) ExtractMessage() *protocol.Message {
return &protocol.Message{
Payloads: k.GetPayloads(),
Metadata: k.GetMetadata(),
Protocol: k.GetProtocol(),
Version: uint(k.GetVersion()),
}
}
func (k ValKeyshare) RefreshFunc() (RefreshFunc, error) {
curve := curves.K256()
return dklsv1.NewAliceRefresh(curve, k.ExtractMessage(), protocol.Version1)
}
func (k ValKeyshare) SignFunc(msg []byte) (SignFunc, error) {
curve := curves.K256()
return dklsv1.NewAliceSign(curve, sha3.New256(), msg, k.ExtractMessage(), protocol.Version1)
}
func (v ValKeyshare) Marshal() (string, error) {
jsonBytes, err := json.Marshal(v)
return string(jsonBytes), err
}
func (v ValKeyshare) Unmarshal(data string) error {
return json.Unmarshal([]byte(data), &v)
}
type UserKeyshare struct {
Message Message `json:"message"` // BobOutput
Role int `json:"role"` // 2 for user, 1 for validator
PublicKey []byte `json:"public-key"`
}
func NewUserKeyshare(msg Message) (*UserKeyshare, error) {
out, err := dklsv1.DecodeBobDkgResult(msg)
if err != nil {
return nil, err
}
return &UserKeyshare{
Message: msg,
Role: 2,
PublicKey: out.PublicKey.ToAffineUncompressed(),
}, nil
}
func (u UserKeyshare) GetPayloads() map[string][]byte {
return u.Message.Payloads
}
func (u UserKeyshare) GetMetadata() map[string]string {
return u.Message.Metadata
}
func (u UserKeyshare) GetPublicKey() []byte {
return u.PublicKey
}
func (u UserKeyshare) GetProtocol() string {
return u.Message.Protocol
}
func (u UserKeyshare) GetRole() int32 {
return int32(u.Role)
}
func (u UserKeyshare) GetVersion() uint32 {
return uint32(u.Message.Version)
}
func (k UserKeyshare) ECDSAPublicKey() (*ecdsa.PublicKey, error) {
return ComputeEcdsaPublicKey(k.PublicKey)
}
func (k UserKeyshare) ExtractMessage() *protocol.Message {
return &protocol.Message{
Payloads: k.GetPayloads(),
Metadata: k.GetMetadata(),
Protocol: k.GetProtocol(),
Version: uint(k.GetVersion()),
}
}
func (k UserKeyshare) RefreshFunc() (RefreshFunc, error) {
curve := curves.K256()
return dklsv1.NewBobRefresh(curve, k.ExtractMessage(), protocol.Version1)
}
func (k UserKeyshare) SignFunc(msg []byte) (SignFunc, error) {
curve := curves.K256()
return dklsv1.NewBobSign(curve, sha3.New256(), msg, k.ExtractMessage(), protocol.Version1)
}
func (u UserKeyshare) Marshal() (string, error) {
jsonBytes, err := json.Marshal(u)
if err != nil {
return "", err
}
return string(jsonBytes), nil
}
func (u UserKeyshare) Unmarshal(data string) error {
return json.Unmarshal([]byte(data), &u)
}
+112
View File
@@ -0,0 +1,112 @@
package mpc
import (
"fmt"
"time"
"github.com/ucan-wg/go-ucan"
)
type KeyshareSource interface {
ucan.Source
Address() string
Issuer() string
DefaultOriginToken() (*Token, error)
PublicKey() []byte
TokenParser() *ucan.TokenParser
SignData(data []byte) ([]byte, error)
VerifyData(data []byte, sig []byte) (bool, error)
}
func createKeyshareSource(val *ValKeyshare, user *UserKeyshare) (KeyshareSource, error) {
iss, addr, err := ComputeIssuerDID(val.GetPublicKey())
if err != nil {
return nil, err
}
return keyshareSource{
userShare: user,
valShare: val,
addr: addr,
issuerDID: iss,
}, nil
}
// Address returns the address of the keyshare
func (k keyshareSource) Address() string {
return k.addr
}
// Issuer returns the DID of the issuer of the keyshare
func (k keyshareSource) Issuer() string {
return k.issuerDID
}
// PublicKey returns the public key of the keyshare
func (k keyshareSource) PublicKey() []byte {
return k.valShare.PublicKey
}
// DefaultOriginToken returns a default token with the keyshare's issuer as the audience
func (k keyshareSource) DefaultOriginToken() (*Token, error) {
caps := NewSmartAccountCapabilities()
att := CreateSmartAccountAttenuations(caps, k.addr)
zero := time.Time{}
return k.NewOriginToken(k.issuerDID, att, nil, zero, zero)
}
// TokenParser returns a token parser that can be used to parse tokens
func (k keyshareSource) TokenParser() *ucan.TokenParser {
caps := NewSmartAccountCapabilities()
ac := func(m map[string]interface{}) (ucan.Attenuation, error) {
var (
cap string
rsc ucan.Resource
)
for key, vali := range m {
val, ok := vali.(string)
if !ok {
return ucan.Attenuation{}, fmt.Errorf(`expected attenuation value to be a string`)
}
if key == ucan.CapKey {
cap = val
} else {
rsc = ucan.NewStringLengthResource(key, val)
}
}
return ucan.Attenuation{
Rsc: rsc,
Cap: caps.Cap(cap),
}, nil
}
store := ucan.NewMemTokenStore()
return ucan.NewTokenParser(ac, ucan.StringDIDPubKeyResolver{}, store.(ucan.CIDBytesResolver))
}
func (k keyshareSource) SignData(data []byte) ([]byte, error) {
// Create signing functions
signFunc, err := k.userShare.SignFunc(data)
if err != nil {
return nil, fmt.Errorf("failed to create sign function: %w", err)
}
valSignFunc, err := k.valShare.SignFunc(data)
if err != nil {
return nil, fmt.Errorf("failed to create validator sign function: %w", err)
}
// Run the signing protocol
sig, err := RunSignProtocol(valSignFunc, signFunc)
if err != nil {
return nil, fmt.Errorf("failed to run sign protocol: %w", err)
}
return SerializeSignature(sig)
}
func (k keyshareSource) VerifyData(data []byte, sig []byte) (bool, error) {
return VerifySignature(k.userShare.PublicKey, data, sig)
}
+95
View File
@@ -0,0 +1,95 @@
package mpc
import (
"fmt"
"time"
"github.com/golang-jwt/jwt"
"github.com/ucan-wg/go-ucan"
)
type (
Token = ucan.Token
Claims = ucan.Claims
Proof = ucan.Proof
Attenuations = ucan.Attenuations
Fact = ucan.Fact
)
var (
UCANVersion = ucan.UCANVersion
UCANVersionKey = ucan.UCANVersionKey
PrfKey = ucan.PrfKey
FctKey = ucan.FctKey
AttKey = ucan.AttKey
CapKey = ucan.CapKey
)
type keyshareSource struct {
userShare *UserKeyshare
valShare *ValKeyshare
addr string
issuerDID string
}
func (k keyshareSource) NewOriginToken(audienceDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*ucan.Token, error) {
return k.newToken(audienceDID, nil, att, fct, notBefore, expires)
}
func (k keyshareSource) NewAttenuatedToken(parent *Token, audienceDID string, att ucan.Attenuations, fct []ucan.Fact, nbf, exp time.Time) (*Token, error) {
if !parent.Attenuations.Contains(att) {
return nil, fmt.Errorf("scope of ucan attenuations must be less than it's parent")
}
return k.newToken(audienceDID, append(parent.Proofs, Proof(parent.Raw)), att, fct, nbf, exp)
}
func (k keyshareSource) newToken(audienceDID string, prf []Proof, att Attenuations, fct []Fact, nbf, exp time.Time) (*ucan.Token, error) {
t := jwt.New(newMPCSigningMethod("MPC256", k))
// if _, err := did.Parse(audienceDID); err != nil {
// return nil, fmt.Errorf("invalid audience DID: %w", err)
// }
t.Header[UCANVersionKey] = UCANVersion
var (
nbfUnix int64
expUnix int64
)
if !nbf.IsZero() {
nbfUnix = nbf.Unix()
}
if !exp.IsZero() {
expUnix = exp.Unix()
}
// set our claims
t.Claims = &Claims{
StandardClaims: &jwt.StandardClaims{
Issuer: k.issuerDID,
Audience: audienceDID,
NotBefore: nbfUnix,
// set the expire time
// see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4
ExpiresAt: expUnix,
},
Attenuations: att,
Facts: fct,
Proofs: prf,
}
raw, err := t.SignedString(nil)
if err != nil {
return nil, err
}
return &Token{
Raw: raw,
Attenuations: att,
Facts: fct,
Proofs: prf,
}, nil
}
+107
View File
@@ -0,0 +1,107 @@
package mpc
import (
genericecdsa "crypto/ecdsa"
"fmt"
"math/big"
"github.com/cosmos/cosmos-sdk/types/bech32"
"github.com/onsonr/sonr/pkg/crypto/core/curves"
"github.com/onsonr/sonr/pkg/crypto/core/protocol"
"golang.org/x/crypto/sha3"
)
func ComputeIssuerDID(pk []byte) (string, string, error) {
addr, err := ComputeSonrAddr(pk)
if err != nil {
return "", "", err
}
return fmt.Sprintf("did:sonr:%s", addr), addr, nil
}
func ComputeSonrAddr(pk []byte) (string, error) {
sonrAddr, err := bech32.ConvertAndEncode("idx", pk)
if err != nil {
return "", err
}
return sonrAddr, nil
}
// For DKG bob starts first. For refresh and sign, Alice starts first.
func runIteratedProtocol(firstParty protocol.Iterator, secondParty protocol.Iterator) (error, error) {
var (
message *protocol.Message
aErr error
bErr error
)
for aErr != protocol.ErrProtocolFinished || bErr != protocol.ErrProtocolFinished {
// Crank each protocol forward one iteration
message, bErr = firstParty.Next(message)
if bErr != nil && bErr != protocol.ErrProtocolFinished {
return nil, bErr
}
message, aErr = secondParty.Next(message)
if aErr != nil && aErr != protocol.ErrProtocolFinished {
return aErr, nil
}
}
return aErr, bErr
}
// ComputeEcPoint builds an elliptic curve point from a compressed byte slice
func ComputeEcPoint(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)
}
return &curves.EcPoint{X: x, Y: y, Curve: ecCurve}, nil
}
func ComputeEcdsaPublicKey(pubKey []byte) (*genericecdsa.PublicKey, error) {
pk, err := ComputeEcPoint(pubKey)
if err != nil {
return nil, err
}
return &genericecdsa.PublicKey{
Curve: pk.Curve,
X: pk.X,
Y: pk.Y,
}, nil
}
// VerifySignature verifies the signature of a message
func VerifySignature(pk []byte, msg []byte, sig []byte) (bool, error) {
pp, err := ComputeEcPoint(pk)
if err != nil {
return false, err
}
sigEd, err := DeserializeSignature(sig)
if err != nil {
return false, err
}
hash := sha3.New256()
_, err = hash.Write(msg)
if err != nil {
return false, err
}
digest := hash.Sum(nil)
return curves.VerifyEcdsa(pp, digest[:], sigEd), nil
}
func checkIteratedErrors(aErr, bErr error) error {
if aErr == protocol.ErrProtocolFinished && bErr == protocol.ErrProtocolFinished {
return nil
}
if aErr != protocol.ErrProtocolFinished {
return aErr
}
if bErr != protocol.ErrProtocolFinished {
return bErr
}
return nil
}