Skip to content

Commit

Permalink
Merge pull request #34 from 0xPolygonID/feature/onchain-revocation-st…
Browse files Browse the repository at this point in the history
…atus

Feature/onchain revocation status
  • Loading branch information
olomix authored Jun 26, 2023
2 parents e50e452 + 5d5013f commit 3ef54da
Show file tree
Hide file tree
Showing 10 changed files with 691 additions and 34 deletions.
23 changes: 1 addition & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,4 @@ clang -L../ios -lpolygonid-darwin-arm64 \
-framework CoreServices \
`pkg-config --libs --cflags libcjson` \
json_functions_tests.c && ./a.out
```

## Generate StateV2 contract ABI
The contract can be found in a different repository located at
https://github.com/iden3/contracts. To generate the StateV2.go file again, you
need `abigen` command installed from
https://github.com/ethereum/go-ethereum/tree/master/cmd/abigen.
Then it is required to run following commands from `contracts` repository
```bash
npm install
# Compile the contracts. After this command file
# artifacts/contracts/state/StateV2.sol/StateV2.json should appear.
# E2E_PUBLISHING_KEY env is required but not used, so we can put anything
# in it.
E2E_PUBLISHING_KEY=1111111111111111111111111111111111111111111111111111111111111111 npm run compile
# Extract bytecode from compiled artifacts to StateV2.bcode file
jq -r .bytecode artifacts/contracts/state/StateV2.sol/StateV2.json > StateV2.bcode
# Extract ABI from compiled artifacts to StateV2.abi file
jq .abi artifacts/contracts/state/StateV2.sol/StateV2.json > StateV2.abi
# Generate Go package from ABI.
`go env GOPATH`/bin/abigen --bin=StateV2.bcode --abi=StateV2.abi --pkg=c_polygonid --out=../c-polygonid/StateV2.go
```
```
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/0xPolygonID/c-polygonid
go 1.19

require (
github.com/ethereum/go-ethereum v1.11.5
github.com/ethereum/go-ethereum v1.12.0
github.com/iden3/contracts-abi/state/go/abi v0.0.0-20230405152923-4a25f6f1f0f4
github.com/iden3/go-circuits v1.0.2
github.com/iden3/go-iden3-core v1.0.2
Expand All @@ -30,7 +30,8 @@ require (
github.com/go-stack/stack v1.8.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/holiman/uint256 v1.2.0 // indirect
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect
github.com/iden3/contracts-abi/onchain-credential-status-resolver/go/abi v0.0.0-20230623092404-d47a0a434f65 // indirect
github.com/ipfs/boxo v0.8.0 // indirect
github.com/ipfs/go-cid v0.4.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
Expand Down Expand Up @@ -59,7 +60,7 @@ require (
github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/sys v0.7.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
20 changes: 12 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ=
github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo=
github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0=
github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
Expand All @@ -61,7 +60,7 @@ github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoB
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
Expand All @@ -70,10 +69,14 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8=
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
github.com/iden3/contracts-abi/identityBase/go/abi v0.0.0-20230621153633-7549c4edaf16 h1:ZK0P87QMoUejpFAJ3egkAKj3IpSCtRRf/ztgZGcFQW4=
github.com/iden3/contracts-abi/identityBase/go/abi v0.0.0-20230621153633-7549c4edaf16/go.mod h1:VazDjFNz60ZVIZ0twlDRbW+4xp3IE+rLTbJQWSm11cQ=
github.com/iden3/contracts-abi/onchain-credential-status-resolver/go/abi v0.0.0-20230623092404-d47a0a434f65 h1:K8dUsVWB2FMSK/4+Vyg3U6khNGkGFzJChJmcGNjm/KY=
github.com/iden3/contracts-abi/onchain-credential-status-resolver/go/abi v0.0.0-20230623092404-d47a0a434f65/go.mod h1:8fkd2xyUG/V7ovpvZRyD2LyK2zZ4ALbgf5vJGyhzKdg=
github.com/iden3/contracts-abi/state/go/abi v0.0.0-20230405152923-4a25f6f1f0f4 h1:iPvYa/AhhGo3juoUFDm/fBE2CZKy4WfQu7JY90tRf9Q=
github.com/iden3/contracts-abi/state/go/abi v0.0.0-20230405152923-4a25f6f1f0f4/go.mod h1:TxgIrXCvxms3sbOdsy8kTvffUCIpEEifNy0fSXdkU4w=
github.com/iden3/go-circuits v1.0.2 h1:6hxPbaxS1YaSZh36K5I8Nb1WAnUdYC9VK5Hqgyhh1EY=
Expand Down Expand Up @@ -207,8 +210,8 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
Expand All @@ -220,6 +223,7 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
Expand Down
156 changes: 155 additions & 1 deletion inputs_sig.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import (
"math/big"
"net/http"
"net/url"
"strconv"
"strings"
"time"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
onchainABI "github.com/iden3/contracts-abi/onchain-credential-status-resolver/go/abi"
"github.com/iden3/contracts-abi/state/go/abi"
"github.com/iden3/go-circuits"
core "github.com/iden3/go-iden3-core"
Expand Down Expand Up @@ -259,7 +261,7 @@ func buildAndValidateCredentialStatus(ctx context.Context, cfg EnvConfig,
proofValid := merkletree.VerifyProof(proof.TreeState.RevocationRoot,
proof.Proof, revNonce, big.NewInt(0))
if !proofValid {
return proof, errors.New("proof validation failed")
return proof, fmt.Errorf("proof validation failed. revNonce=%d", revNonce)
}

if proof.Proof.Existence {
Expand Down Expand Up @@ -1129,6 +1131,8 @@ func claimWithMtpProofFromObj(ctx context.Context, cfg EnvConfig,
return out, err
}

} else if proofI = findProofByType(w3cCred, verifiable.ProofType(verifiable.Iden3OnchainSparseMerkleTreeProof2023)); proofI != nil {

} else {
return out, fmt.Errorf("no %v proofs found",
verifiable.Iden3SparseMerkleTreeProofType)
Expand Down Expand Up @@ -1207,6 +1211,9 @@ func resolveRevStatus(ctx context.Context,
}
return resolveRevStatusFromRHS(ctx, cfg, issuerID, revNonce)
case *verifiable.CredentialStatus:
if status.Type == verifiable.Iden3OnchainSparseMerkleTreeProof2023 {
return resolverOnChainRevocationStatus(ctx, cfg, issuerID, status)
}
return resolveRevocationStatusFromIssuerService(ctx, status.ID)
case verifiable.RHSCredentialStatus:
return resolveRevStatus(ctx, cfg, &status, issuerID)
Expand All @@ -1228,6 +1235,8 @@ func resolveRevStatus(ctx context.Context,
s = &verifiable.RHSCredentialStatus{}
case verifiable.SparseMerkleTreeProof:
s = &verifiable.CredentialStatus{}
case verifiable.Iden3OnchainSparseMerkleTreeProof2023:
s = &verifiable.CredentialStatus{}
default:
return circuits.MTProof{}, fmt.Errorf(
"credential status type %s id not supported",
Expand All @@ -1246,6 +1255,151 @@ func resolveRevStatus(ctx context.Context,
}
}

// Currently, our library does not have a Close function. As a result, we
// create and destroy an Ethereum client for each usage of this function.
// Although this approach may be inefficient, it is acceptable if the function
// is rarely called. If this becomes an issue in the future, or if a Close
// function is implemented, we will need to refactor this function to use a
// global Ethereum client.
func resolverOnChainRevocationStatus(ctx context.Context, cfg EnvConfig, id *core.ID,
status *verifiable.CredentialStatus) (circuits.MTProof, error) {

if cfg.EthereumURL == "" {
return circuits.MTProof{}, errors.New("ethereum url is empty")
}

var zeroID core.ID
if id == nil || *id == zeroID {
return circuits.MTProof{}, errors.New("issuer ID is empty")
}

uri, err := url.Parse(status.ID)
if err != nil {
return circuits.MTProof{}, errors.New("OnChainCredentialStatus ID is not a valid URI")
}
contract := uri.Query().Get("contractAddress")
if contract == "" {
return circuits.MTProof{}, errors.New("OnChainCredentialStatus contract address is empty")
}
contractAddress := common.HexToAddress(strings.Split(contract, ":")[1])

revocationNonce := uri.Query().Get("revocationNonce")
if revocationNonce == "" {
return circuits.MTProof{}, errors.New("revocationNonce is empty in OnChainCredentialStatus ID")
}

revocationNonceInt, err := strconv.ParseUint(revocationNonce, 10, 64)
if err != nil {
return circuits.MTProof{}, errors.New("revocationNonce is not a number in OnChainCredentialStatus ID")
}

if revocationNonceInt != status.RevocationNonce {
return circuits.MTProof{},
fmt.Errorf("revocation revocationNonce is not equal to the one in OnChainCredentialStatus ID"+
" {%d} {%d}", revocationNonceInt, status.RevocationNonce)
}

client, err := ethclient.Dial(cfg.EthereumURL)
if err != nil {
return circuits.MTProof{}, err
}
defer client.Close()

contractCaller, err := onchainABI.NewOnchainCredentialStatusResolverCaller(contractAddress, client)
if err != nil {
return circuits.MTProof{}, err
}

// TODO: it is not finial version of contract GetRevocationProof must accept issuer id as parameter
resp, err := contractCaller.GetRevocationStatus(
&bind.CallOpts{Context: ctx},
id.BigInt(),
revocationNonceInt)
if err != nil {
return circuits.MTProof{}, fmt.Errorf("GetRevocationProof smart contract call, %s", err.Error())
}

return toMerkleTreeProof(resp)
}

func toMerkleTreeProof(status onchainABI.IOnchainCredentialStatusResolverCredentialStatus) (circuits.MTProof, error) {
var existence bool
var nodeAux *merkletree.NodeAux
var err error

if status.Mtp.Existence {
existence = true
} else {
existence = false
if status.Mtp.AuxExistence {
nodeAux = &merkletree.NodeAux{}
nodeAux.Key, err = merkletree.NewHashFromBigInt(status.Mtp.AuxIndex)
if err != nil {
return circuits.MTProof{}, errors.New("aux index is not a number")
}
nodeAux.Value, err = merkletree.NewHashFromBigInt(status.Mtp.AuxValue)
if err != nil {
return circuits.MTProof{}, errors.New("aux value is not a number")
}
}
}

//allSiblings := make([]*merkletree.Hash, len(status.Mtp.Siblings))
depth := calculateDepth(status.Mtp.Siblings)
allSiblings := make([]*merkletree.Hash, depth)
for i := 0; i < depth; i++ {
sh, err2 := merkletree.NewHashFromBigInt(status.Mtp.Siblings[i])
if err2 != nil {
return circuits.MTProof{}, errors.New("sibling is not a number")
}
allSiblings[i] = sh
}

proof, err := merkletree.NewProofFromData(existence, allSiblings, nodeAux)
if err != nil {
return circuits.MTProof{}, errors.New("failed to create proof")
}

state, err := merkletree.NewHashFromBigInt(status.Issuer.State)
if err != nil {
return circuits.MTProof{}, errors.New("state is not a number")
}

claimsRoot, err := merkletree.NewHashFromBigInt(status.Issuer.ClaimsTreeRoot)
if err != nil {
return circuits.MTProof{}, errors.New("state is not a number")
}

revocationRoot, err := merkletree.NewHashFromBigInt(status.Issuer.RevocationTreeRoot)
if err != nil {
return circuits.MTProof{}, errors.New("state is not a number")
}

rootOfRoots, err := merkletree.NewHashFromBigInt(status.Issuer.RootOfRoots)
if err != nil {
return circuits.MTProof{}, errors.New("state is not a number")
}

return circuits.MTProof{
Proof: proof,
TreeState: circuits.TreeState{
State: state,
ClaimsRoot: claimsRoot,
RevocationRoot: revocationRoot,
RootOfRoots: rootOfRoots,
},
}, nil
}

func calculateDepth(siblings []*big.Int) int {
for i := len(siblings) - 1; i >= 0; i-- {
if siblings[i].Cmp(big.NewInt(0)) != 0 {
return i + 1
}
}
return 0
}

type EnvConfig struct {
EthereumURL string
StateContractAddr common.Address
Expand Down
Loading

0 comments on commit 3ef54da

Please sign in to comment.