Skip to content

Commit

Permalink
add timestamp proof generation check (#53)
Browse files Browse the repository at this point in the history
* add timestamp proof generation check
  • Loading branch information
volodymyr-basiuk authored Jul 11, 2023
1 parent 6c6c69e commit 6428e71
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 11 deletions.
2 changes: 1 addition & 1 deletion auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ func (v *Verifier) VerifyAuthResponse(
rawMessage = nil
}

err = cv.VerifyQuery(ctx, query, v.claimSchemaLoader, rawMessage)
err = cv.VerifyQuery(ctx, query, v.claimSchemaLoader, rawMessage, opts...)
if err != nil {
return err
}
Expand Down
13 changes: 8 additions & 5 deletions auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"math/big"
"testing"
"time"

"github.com/google/uuid"
"github.com/iden3/go-circuits"
Expand Down Expand Up @@ -283,6 +284,8 @@ var stateResolvers = map[string]pubsignals.StateResolver{
"polygon:mumbai": &mockStateResolver{},
}

const proofGenerationDelay = time.Hour * 100000

type mockStateResolver struct {
}

Expand Down Expand Up @@ -613,7 +616,7 @@ func TestVerifyMessageWithMTPProof_Merkalized(t *testing.T) {
schemaLoader := &mockJSONLDSchemaLoader{schema: kycV3Schema}
authInstance, err := NewVerifierWithExplicitError(verificationKeyloader, schemaLoader, stateResolvers)
require.NoError(t, err)
err = authInstance.VerifyAuthResponse(context.Background(), message, request)
err = authInstance.VerifyAuthResponse(context.Background(), message, request, pubsignals.WithAcceptedProofGenerationDelay(proofGenerationDelay))
require.NoError(t, err)
}

Expand Down Expand Up @@ -665,7 +668,7 @@ func TestVerifier_FullVerify(t *testing.T) {
schemaLoader := &mockJSONLDSchemaLoader{schema: kycV3Schema}
authInstance, err := NewVerifierWithExplicitError(verificationKeyloader, schemaLoader, stateResolvers)
require.NoError(t, err)
_, err = authInstance.FullVerify(context.Background(), token, request)
_, err = authInstance.FullVerify(context.Background(), token, request, pubsignals.WithAcceptedProofGenerationDelay(proofGenerationDelay))
require.NoError(t, err)
}

Expand Down Expand Up @@ -702,7 +705,7 @@ func TestVerifier_FullVerify_JWS(t *testing.T) {
err = pm.RegisterPackers(jwsPacker)
require.NoError(t, err)
v.SetPackageManager(pm)
_, err = v.FullVerify(context.Background(), token, request)
_, err = v.FullVerify(context.Background(), token, request, pubsignals.WithAcceptedProofGenerationDelay(proofGenerationDelay))
require.NoError(t, err)
}

Expand Down Expand Up @@ -921,7 +924,7 @@ func TestVerifier_FullVerifySelectiveDisclosure(t *testing.T) {
schemaLoader := &mockJSONLDSchemaLoader{schema: kycV4Schema}
authInstance, err := NewVerifierWithExplicitError(verificationKeyloader, schemaLoader, stateResolvers)
require.NoError(t, err)
_, err = authInstance.FullVerify(context.Background(), token, request)
_, err = authInstance.FullVerify(context.Background(), token, request, pubsignals.WithAcceptedProofGenerationDelay(proofGenerationDelay))
require.NoError(t, err)
}

Expand Down Expand Up @@ -951,6 +954,6 @@ func TestEmptyCredentialSubject(t *testing.T) {
schemaLoader := &mockJSONLDSchemaLoader{schema: kycV101Schema}
authInstance, err := NewVerifierWithExplicitError(verificationKeyloader, schemaLoader, stateResolvers)
require.NoError(t, err)
_, err = authInstance.FullVerify(context.Background(), token, request)
_, err = authInstance.FullVerify(context.Background(), token, request, pubsignals.WithAcceptedProofGenerationDelay(proofGenerationDelay))
require.NoError(t, err)
}
3 changes: 2 additions & 1 deletion pubsignals/atomicMtpV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func (c *AtomicQueryMTPV2) VerifyQuery(
query Query,
schemaLoader loaders.SchemaLoader,
verifiablePresentation json.RawMessage,
opts ...VerifyOpt,
) error {
return query.Check(ctx, schemaLoader, &CircuitOutputs{
IssuerID: c.IssuerID,
Expand All @@ -37,7 +38,7 @@ func (c *AtomicQueryMTPV2) VerifyQuery(
ClaimPathNotExists: c.ClaimPathNotExists,
ValueArraySize: c.ValueArraySize,
IsRevocationChecked: c.IsRevocationChecked,
}, verifiablePresentation)
}, verifiablePresentation, opts...)
}

// VerifyStates verifies user state and issuer claim issuance state in the smart contract.
Expand Down
3 changes: 2 additions & 1 deletion pubsignals/atomicSigV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func (c *AtomicQuerySigV2) VerifyQuery(
query Query,
schemaLoader loaders.SchemaLoader,
verifiablePresentation json.RawMessage,
opts ...VerifyOpt,
) error {
err := query.Check(ctx, schemaLoader, &CircuitOutputs{
IssuerID: c.IssuerID,
Expand All @@ -37,7 +38,7 @@ func (c *AtomicQuerySigV2) VerifyQuery(
ClaimPathNotExists: c.ClaimPathNotExists,
ValueArraySize: c.ValueArraySize,
IsRevocationChecked: c.IsRevocationChecked,
}, verifiablePresentation)
}, verifiablePresentation, opts...)
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion pubsignals/authV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ func (c *AuthV2) VerifyQuery(
_ context.Context,
_ Query,
_ loaders.SchemaLoader,
_ json.RawMessage) error {
_ json.RawMessage,
_ ...VerifyOpt) error {
return errors.New("authV2 circuit doesn't support queries")
}

Expand Down
2 changes: 1 addition & 1 deletion pubsignals/circuitVerifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type StateResolver interface {

// Verifier is interface for verification of public signals of zkp
type Verifier interface {
VerifyQuery(ctx context.Context, query Query, schemaLoader loaders.SchemaLoader, verifiablePresentation json.RawMessage) error
VerifyQuery(ctx context.Context, query Query, schemaLoader loaders.SchemaLoader, verifiablePresentation json.RawMessage, opts ...VerifyOpt) error
VerifyStates(ctx context.Context, resolvers map[string]StateResolver, opts ...VerifyOpt) error
VerifyIDOwnership(userIdentifier string, challenge *big.Int) error

Expand Down
13 changes: 13 additions & 0 deletions pubsignals/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"math/big"
"strconv"
"time"

"github.com/iden3/go-circuits"
"github.com/iden3/go-iden3-auth/loaders"
Expand Down Expand Up @@ -86,6 +87,7 @@ func (q Query) Check(
loader loaders.SchemaLoader,
pubSig *CircuitOutputs,
verifiablePresentation json.RawMessage,
opts ...VerifyOpt,
) error {
if err := q.verifyIssuer(pubSig); err != nil {
return err
Expand All @@ -112,6 +114,17 @@ func (q Query) Check(
return errors.New("check revocation is required")
}

cfg := defaultProofVerifyOpts
for _, o := range opts {
o(&cfg)
}

if time.Since(
time.Unix(pubSig.Timestamp, 0),
) > cfg.acceptedProofGenerationDelay {
return ErrProofGenerationOutdated
}

return q.verifyClaim(ctx, schemaBytes, pubSig)
}

Expand Down
54 changes: 54 additions & 0 deletions pubsignals/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"math/big"
"testing"
"time"

core "github.com/iden3/go-iden3-core"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -163,6 +164,7 @@ var vpEmployee = []byte(`{
}`)

func TestCheckRequest_Success(t *testing.T) {
now := time.Now().Unix()
tests := []struct {
name string
query Query
Expand Down Expand Up @@ -192,6 +194,7 @@ func TestCheckRequest_Success(t *testing.T) {
Value: []*big.Int{big.NewInt(800)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
},
{
Expand All @@ -215,6 +218,7 @@ func TestCheckRequest_Success(t *testing.T) {
Value: []*big.Int{big.NewInt(800)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
vp: vp,
},
Expand All @@ -241,6 +245,7 @@ func TestCheckRequest_Success(t *testing.T) {
Value: []*big.Int{bigIntTrueHash},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
},
{
Expand All @@ -267,6 +272,7 @@ func TestCheckRequest_Success(t *testing.T) {
}(),
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
vp: vpEmployee,
},
Expand Down Expand Up @@ -296,6 +302,7 @@ func TestCheckRequest_Success(t *testing.T) {
}(),
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
vp: vpEmployee,
},
Expand All @@ -310,13 +317,43 @@ func TestCheckRequest_Success(t *testing.T) {
}

func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) {
now := time.Now().Unix()
durationMin, _ := time.ParseDuration("-1m")
dayAndMinuteAgo := time.Now().AddDate(0, 0, -1).Add(durationMin).Unix()
tests := []struct {
name string
query Query
pubSig *CircuitOutputs
vp json.RawMessage
expErr error
}{
{
name: "Generated proof is outdated",
query: Query{
AllowedIssuers: []string{"*"},
CredentialSubject: map[string]interface{}{
"countryCode": map[string]interface{}{
"$nin": []interface{}{float64(800)},
},
},
Context: "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld",
Type: "KYCCountryOfResidenceCredential",
},
pubSig: &CircuitOutputs{
IssuerID: &issuerID,
ClaimSchema: KYCCountrySchema,
ClaimPathKey: func() *big.Int {
v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10)
return v
}(),
Operator: 5,
Value: []*big.Int{big.NewInt(800)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: dayAndMinuteAgo,
},
expErr: errors.New("generated proof is outdated"),
},
{
name: "Empty disclosure value for disclosure request",
query: Query{
Expand All @@ -339,6 +376,7 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) {
Value: []*big.Int{big.NewInt(800)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
expErr: errors.New("selective disclosure value is missed"),
},
Expand All @@ -364,6 +402,7 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) {
Value: []*big.Int{big.NewInt(800)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
expErr: errors.New("selective disclosure available only for equal operation"),
},
Expand All @@ -389,6 +428,7 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) {
Value: []*big.Int{big.NewInt(800), big.NewInt(801)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
expErr: errors.New("selective disclosure not available for array of values"),
},
Expand All @@ -414,6 +454,7 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) {
Value: []*big.Int{big.NewInt(1)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
expErr: errors.New("different value between proof and disclosure value"),
},
Expand All @@ -439,6 +480,7 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) {
Value: []*big.Int{big.NewInt(800)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
expErr: errors.New("path '[https://www.w3.org/2018/credentials#verifiableCredential https://www.w3.org/2018/credentials#credentialSubject https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#documentType]' doesn't exist in document"),
},
Expand All @@ -453,6 +495,7 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) {
}

func TestCheckRequest_Error(t *testing.T) {
now := time.Now().Unix()
tests := []struct {
name string
query Query
Expand All @@ -479,6 +522,7 @@ func TestCheckRequest_Error(t *testing.T) {
pubSig: &CircuitOutputs{
IssuerID: &issuerID,
ClaimSchema: KYCCountrySchema,
Timestamp: now,
},
expErr: ErrSchemaID,
},
Expand All @@ -496,6 +540,7 @@ func TestCheckRequest_Error(t *testing.T) {
pubSig: &CircuitOutputs{
IssuerID: &issuerID,
ClaimSchema: KYCCountrySchema,
Timestamp: now,
},
expErr: errors.New("multiple requests not supported"),
},
Expand All @@ -512,6 +557,7 @@ func TestCheckRequest_Error(t *testing.T) {
pubSig: &CircuitOutputs{
IssuerID: &issuerID,
ClaimSchema: KYCCountrySchema,
Timestamp: now,
},
expErr: errors.New("failed cast type map[string]interface"),
},
Expand All @@ -531,6 +577,7 @@ func TestCheckRequest_Error(t *testing.T) {
pubSig: &CircuitOutputs{
IssuerID: &issuerID,
ClaimSchema: KYCCountrySchema,
Timestamp: now,
},
expErr: errors.New("multiple predicates for one field not supported"),
},
Expand All @@ -550,6 +597,7 @@ func TestCheckRequest_Error(t *testing.T) {
IssuerID: &issuerID,
ClaimSchema: KYCCountrySchema,
Operator: 3,
Timestamp: now,
},
expErr: ErrRequestOperator,
},
Expand All @@ -570,6 +618,7 @@ func TestCheckRequest_Error(t *testing.T) {
ClaimSchema: KYCCountrySchema,
Operator: 5,
Value: []*big.Int{big.NewInt(40)},
Timestamp: now,
},
expErr: ErrInvalidValues,
},
Expand All @@ -593,6 +642,7 @@ func TestCheckRequest_Error(t *testing.T) {
Value: []*big.Int{big.NewInt(20)},
Merklized: 1,
IsRevocationChecked: 1,
Timestamp: now,
},
expErr: errors.New("proof was generated for another path"),
},
Expand All @@ -616,6 +666,7 @@ func TestCheckRequest_Error(t *testing.T) {
Merklized: 0,
SlotIndex: 0,
IsRevocationChecked: 1,
Timestamp: now,
},
expErr: errors.New("different slot index for claim"),
},
Expand All @@ -640,6 +691,7 @@ func TestCheckRequest_Error(t *testing.T) {
Merklized: 0,
SlotIndex: 0,
IsRevocationChecked: 0,
Timestamp: now,
},
expErr: errors.New("check revocation is required"),
},
Expand All @@ -664,6 +716,7 @@ func TestCheckRequest_Error(t *testing.T) {
Merklized: 0,
SlotIndex: 0,
IsRevocationChecked: 0,
Timestamp: now,
},
expErr: errors.New("invalid operation '$lt' for field type 'http://www.w3.org/2001/XMLSchema#boolean'"),
},
Expand All @@ -688,6 +741,7 @@ func TestCheckRequest_Error(t *testing.T) {
Merklized: 0,
SlotIndex: 0,
IsRevocationChecked: 0,
Timestamp: now,
},
expErr: ErrNegativeValue,
},
Expand Down
Loading

0 comments on commit 6428e71

Please sign in to comment.