Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add optional parameter to packer.Unpack #60

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions mock/proving.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,6 @@ func PrepareAuthInputs(hash []byte, _ *w3c.DID, _ circuits.CircuitID) ([]byte, e
return j, err
}

// VerifyState return no error always
func VerifyState(_ circuits.CircuitID, _ []string) error {
return nil
}

// MockRecipientKeyID is mocked key id for recipient
const MockRecipientKeyID = "123456789"

Expand Down
10 changes: 5 additions & 5 deletions packager.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Packer interface {
// Pack a payload of type ContentType in an Iden3 compliant format using the packer identity
Pack(payload []byte, params PackerParams) ([]byte, error)
// Unpack an envelope in Iden3 compliant format.
Unpack(envelope []byte) (*BasicMessage, error)
Unpack(envelope []byte, params ...PackerParams) (*BasicMessage, error)
// MediaType returns content type of message
MediaType() MediaType
}
Expand Down Expand Up @@ -65,14 +65,14 @@ func (r *PackageManager) Pack(mediaType MediaType, payload []byte, params Packer

// Unpack returns iden3 message method from envelope
// if it's not valid or can't be decrypted error is returned
func (r *PackageManager) Unpack(envelope []byte) (*BasicMessage, MediaType, error) {
func (r *PackageManager) Unpack(envelope []byte, params ...PackerParams) (*BasicMessage, MediaType, error) {
safeEnvelope := strings.Trim(strings.TrimSpace(string(envelope)), "\"")
mediaType, err := r.GetMediaType([]byte(safeEnvelope))
if err != nil {
return nil, "", err
}

msg, err := r.unpackSafeEnvelope(mediaType, []byte(safeEnvelope))
msg, err := r.unpackSafeEnvelope(mediaType, []byte(safeEnvelope), params...)
if err != nil {
return nil, mediaType, err
}
Expand All @@ -85,14 +85,14 @@ func (r *PackageManager) UnpackWithType(mediaType MediaType, envelope []byte) (*
return r.unpackSafeEnvelope(mediaType, []byte(safeEnvelope))
}

func (r *PackageManager) unpackSafeEnvelope(mediaType MediaType, envelope []byte) (*BasicMessage, error) {
func (r *PackageManager) unpackSafeEnvelope(mediaType MediaType, envelope []byte, params ...PackerParams) (*BasicMessage, error) {
p, ok := r.packers[mediaType]
if !ok {
return nil, errors.Errorf("packer for media type %s doesn't exist", mediaType)
}

// safeEnvelope can be rather base64 encoded or valid json
msg, err := p.Unpack(envelope)
msg, err := p.Unpack(envelope, params...)
if err != nil {
return nil, err
}
Expand Down
8 changes: 7 additions & 1 deletion packager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/google/uuid"
"github.com/iden3/go-circuits/v2"
"github.com/iden3/go-iden3-core/v2/w3c"
"github.com/iden3/go-jwz/v2"
"github.com/iden3/iden3comm/v2"
Expand Down Expand Up @@ -182,7 +183,7 @@ func initPackageManager(t *testing.T) *iden3comm.PackageManager {

mockVerificationParam := make(map[jwz.ProvingMethodAlg]packers.VerificationParams)
mockVerificationParam[mockedProvingMethod.ProvingMethodAlg] = packers.NewVerificationParams([]byte(""),
mock.VerifyState)
verifyStateMock)

mockProvingParamMap := make(map[jwz.ProvingMethodAlg]packers.ProvingParams)
mockProvingParamMap[mockedProvingMethod.ProvingMethodAlg] = packers.NewProvingParams(mock.PrepareAuthInputs,
Expand All @@ -193,3 +194,8 @@ func initPackageManager(t *testing.T) *iden3comm.PackageManager {

return pm
}

// VerifyState return no error always
func verifyStateMock(_ circuits.CircuitID, _ []string, _ ...packers.ZKPPUnpackerParams) error {
return nil
}
2 changes: 1 addition & 1 deletion packers/anoncrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (p *AnoncryptPacker) Pack(payload []byte, params iden3comm.PackerParams) ([
}

// Unpack returns unpacked message from transport envelope
func (p *AnoncryptPacker) Unpack(envelope []byte) (*iden3comm.BasicMessage, error) {
func (p *AnoncryptPacker) Unpack(envelope []byte, _ ...iden3comm.PackerParams) (*iden3comm.BasicMessage, error) {

jwe, err := jose.ParseEncrypted(string(envelope))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion packers/jws.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (p *JWSPacker) Pack(
}

// Unpack returns unpacked message from transport envelope with verification of signature
func (p *JWSPacker) Unpack(envelope []byte) (*iden3comm.BasicMessage, error) {
func (p *JWSPacker) Unpack(envelope []byte, _ ...iden3comm.PackerParams) (*iden3comm.BasicMessage, error) {

token, err := jws.Parse(envelope)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion packers/plain.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (p *PlainMessagePacker) Pack(payload []byte, _ iden3comm.PackerParams) ([]b
}

// Unpack returns unpacked message from transport envelope
func (p *PlainMessagePacker) Unpack(envelope []byte) (*iden3comm.BasicMessage, error) {
func (p *PlainMessagePacker) Unpack(envelope []byte, _ ...iden3comm.PackerParams) (*iden3comm.BasicMessage, error) {

var msg iden3comm.BasicMessage
err := json.Unmarshal(envelope, &msg)
Expand Down
74 changes: 48 additions & 26 deletions packers/zkp.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ func (f DataPreparerHandlerFunc) Prepare(hash []byte, id *w3c.DID, circuitID cir
}

// VerificationHandlerFunc registers the handler function for state verification.
type VerificationHandlerFunc func(id circuits.CircuitID, pubsignals []string) error
type VerificationHandlerFunc func(id circuits.CircuitID, pubsignals []string, opts ...ZKPPUnpackerParams) error

// Verify function is responsible to call provided handler for outputs verification
func (f VerificationHandlerFunc) Verify(id circuits.CircuitID, pubsignals []string) error {
return f(id, pubsignals)
func (f VerificationHandlerFunc) Verify(id circuits.CircuitID, pubsignals []string, params ...ZKPPUnpackerParams) error {
if len(params) > 1 {
return errors.New("expecting no more than one parameter in VerificationHandlerFunc.Verify")
}
return f(id, pubsignals, params...)
}

// VerificationParams defined the verification function and the verification key for ZKP full verification
Expand Down Expand Up @@ -133,14 +136,31 @@ func (p *ZKPPacker) Pack(payload []byte, params iden3comm.PackerParams) ([]byte,
return []byte(tokenStr), nil
}

// Unpack returns unpacked message from transport envelope with verification of zeroknowledge proof
func (p *ZKPPacker) Unpack(envelope []byte) (*iden3comm.BasicMessage, error) {
// ZKPPUnpackerParams is params for zkp unpacker
type ZKPPUnpackerParams struct {
authVerifyDelay time.Duration
iden3comm.PackerParams
}

// NewZKPPUnpackerParams creates new zkp unpacker params
func NewZKPPUnpackerParams(authVerifyDelay time.Duration) ZKPPUnpackerParams {
return ZKPPUnpackerParams{
authVerifyDelay: authVerifyDelay,
}
}

// Unpack returns unpacked message from transport envelope with verification of zero knowledge proof
// params is variadic but only none or one is accepted
func (p *ZKPPacker) Unpack(envelope []byte, params ...iden3comm.PackerParams) (*iden3comm.BasicMessage, error) {

if len(params) > 1 {
return nil, errors.New("expecting no more than one parameter in ZKPPacker Unpack")
}

token, err := jwz.Parse(string(envelope))
if err != nil {
return nil, err
}

verificationKey, ok := p.Verification[jwz.ProvingMethodAlg{Alg: token.Alg, CircuitID: token.CircuitID}]
if !ok {
return nil, fmt.Errorf("message was packed with unsupported circuit `%s` and alg `%s`", token.CircuitID,
Expand All @@ -155,7 +175,13 @@ func (p *ZKPPacker) Unpack(envelope []byte) (*iden3comm.BasicMessage, error) {
return nil, errors.New("message proof is invalid")
}

err = verificationKey.VerificationFn.Verify(circuits.CircuitID(token.CircuitID), token.ZkProof.PubSignals)
var zkParams []ZKPPUnpackerParams
for _, param := range params {
if zkpParam, ok := param.(ZKPPUnpackerParams); ok {
zkParams = append(zkParams, zkpParam)
}
}
err = verificationKey.VerificationFn.Verify(circuits.CircuitID(token.CircuitID), token.ZkProof.PubSignals, zkParams...)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -237,33 +263,21 @@ func (p *ZKPPacker) MediaType() iden3comm.MediaType {
return MediaTypeZKPMessage
}

// DefaultZKPUnpackerOption is a function that sets the default ZKP unpacker options
type DefaultZKPUnpackerOption func(*defaultZKPUnpacker)

// WithAuthVerifyDelay sets the delay for the auth verification
func WithAuthVerifyDelay(delay time.Duration) DefaultZKPUnpackerOption {
return func(p *defaultZKPUnpacker) {
p.authVerifyDelay = delay
}
}

type defaultZKPUnpacker struct {
resolvers map[int]eth.Resolver
authVerifyDelay time.Duration
resolvers map[int]eth.Resolver
}

// DefaultZKPUnpacker creates a default ZKP unpacker with the provided verification key and resolvers
func DefaultZKPUnpacker(verificationKey []byte, resolvers map[int]eth.Resolver, opts ...DefaultZKPUnpackerOption) *ZKPPacker {
def := &defaultZKPUnpacker{resolvers, time.Minute * 5}
for _, opt := range opts {
opt(def)
func DefaultZKPUnpacker(verificationKey []byte, resolvers map[int]eth.Resolver) *ZKPPacker {
def := &defaultZKPUnpacker{
resolvers: resolvers,
}
verifications := make(map[jwz.ProvingMethodAlg]VerificationParams)
verifications[jwz.AuthV2Groth16Alg] = NewVerificationParams(verificationKey, def.defaultZkpUnpackerVerificationFn)
return NewZKPPacker(nil, verifications)
}

func (d *defaultZKPUnpacker) defaultZkpUnpackerVerificationFn(id circuits.CircuitID, pubsignals []string) error {
func (d *defaultZKPUnpacker) defaultZkpUnpackerVerificationFn(id circuits.CircuitID, pubsignals []string, opts ...ZKPPUnpackerParams) error {
if id != circuits.AuthV2CircuitID {
return errors.Errorf("circuit ID '%s' is not supported", id)
}
Expand Down Expand Up @@ -291,7 +305,10 @@ func (d *defaultZKPUnpacker) defaultZkpUnpackerVerificationFn(id circuits.Circui
userDID.String(), err)
}

resolver := d.resolvers[int(chainID)]
resolver, found := d.resolvers[int(chainID)]
if !found {
return errors.Errorf("resolver for chainID '%d' not found", chainID)
}

globalState := authPubSignals.GISTRoot.BigInt()
globalStateInfo, err := resolver.ResolveGist(context.Background(), &services.ResolverOpts{GistRoot: globalState})
Expand All @@ -305,8 +322,13 @@ func (d *defaultZKPUnpacker) defaultZkpUnpackerVerificationFn(id circuits.Circui
globalState.String(), globalStateInfo.Root.String())
}

authVerifyDelay := time.Minute * 5
if len(opts) > 0 {
authVerifyDelay = opts[0].authVerifyDelay
}

if (big.NewInt(0)).Cmp(globalStateInfo.ReplacedByRoot) != 0 &&
time.Since(time.Unix(globalStateInfo.ReplacedAtTimestamp.Int64(), 0)) > d.authVerifyDelay {
time.Since(time.Unix(globalStateInfo.ReplacedAtTimestamp.Int64(), 0)) > authVerifyDelay {
return errors.Errorf("global state is too old, replaced timestamp is %v",
globalStateInfo.ReplacedAtTimestamp.Int64())
}
Expand Down
8 changes: 6 additions & 2 deletions packers/zkp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestZKPPacker_Pack(t *testing.T) {
})

mockVerificationParam := make(map[jwz.ProvingMethodAlg]VerificationParams)
mockVerificationParam[mockedProvingMethod.ProvingMethodAlg] = NewVerificationParams([]byte(""), mock.VerifyState)
mockVerificationParam[mockedProvingMethod.ProvingMethodAlg] = NewVerificationParams([]byte(""), verifyStateMock)

mockProvingParamMap := make(map[jwz.ProvingMethodAlg]ProvingParams)
mockProvingParamMap[mockedProvingMethod.ProvingMethodAlg] =
Expand Down Expand Up @@ -77,7 +77,7 @@ func TestPlainMessagePacker_Unpack(t *testing.T) {
})

mockVerificationParam := make(map[jwz.ProvingMethodAlg]VerificationParams)
mockVerificationParam[mockedProvingMethod.ProvingMethodAlg] = NewVerificationParams([]byte(""), mock.VerifyState)
mockVerificationParam[mockedProvingMethod.ProvingMethodAlg] = NewVerificationParams([]byte(""), verifyStateMock)

mockProvingParamMap := make(map[jwz.ProvingMethodAlg]ProvingParams)
mockProvingParamMap[mockedProvingMethod.ProvingMethodAlg] =
Expand All @@ -101,3 +101,7 @@ func TestPlainMessagePacker_Unpack(t *testing.T) {
assert.Len(t, authResponse.Body.Scope, 0)

}

func verifyStateMock(_ circuits.CircuitID, _ []string, _ ...ZKPPUnpackerParams) error {
return nil
}
Loading