{"id":33589135,"url":"https://github.com/markkurossi/mpc","last_synced_at":"2025-12-14T23:03:53.383Z","repository":{"id":46780936,"uuid":"174100209","full_name":"markkurossi/mpc","owner":"markkurossi","description":"Secure Multi-Party Computation (MPC) with Go. This project implements secure two-party computation with Garbled circuit protocol.","archived":false,"fork":false,"pushed_at":"2025-12-04T06:13:40.000Z","size":11406,"stargazers_count":127,"open_issues_count":4,"forks_count":25,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-12-06T20:15:33.921Z","etag":null,"topics":["aes-128-cbc","aes-128-gcm","ed25519","garbled-circuit","go","golang","hmac-sha256","hmac-sha512","logical-circuits","mpc","multi-party-computation","multiparty-computation","oblivious-transfer","programming-language","sha-256","sha-512","yao-millionaires"],"latest_commit_sha":null,"homepage":"https://www.markkurossi.com/mpcl/index.html","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markkurossi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-03-06T08:05:54.000Z","updated_at":"2025-12-04T06:13:43.000Z","dependencies_parsed_at":"2025-09-19T06:27:21.431Z","dependency_job_id":"b1cc0dd9-e508-4987-ae60-484c095c2b4c","html_url":"https://github.com/markkurossi/mpc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/markkurossi/mpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markkurossi%2Fmpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markkurossi%2Fmpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markkurossi%2Fmpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markkurossi%2Fmpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markkurossi","download_url":"https://codeload.github.com/markkurossi/mpc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markkurossi%2Fmpc/sbom","scorecard":{"id":620138,"data":{"date":"2025-08-11","repo":{"name":"github.com/markkurossi/mpc","commit":"8a4e258ee2b98a9e96e8f18193a6813dc3281d36"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.1,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/18 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yml:1","Warn: no topLevel permission defined: .github/workflows/go.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":1,"reason":"dependency not pinned by hash detected -- score normalized to 1","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/markkurossi/mpc/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/markkurossi/mpc/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:57: update your workflow using https://app.stepsecurity.io/secureworkflow/markkurossi/mpc/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:71: update your workflow using https://app.stepsecurity.io/secureworkflow/markkurossi/mpc/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/markkurossi/mpc/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/markkurossi/mpc/go.yml/master?enable=pin","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (13) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T05:01:07.851Z","repository_id":46780936,"created_at":"2025-08-21T05:01:07.851Z","updated_at":"2025-08-21T05:01:07.851Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27738657,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-14T02:00:11.348Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes-128-cbc","aes-128-gcm","ed25519","garbled-circuit","go","golang","hmac-sha256","hmac-sha512","logical-circuits","mpc","multi-party-computation","multiparty-computation","oblivious-transfer","programming-language","sha-256","sha-512","yao-millionaires"],"created_at":"2025-11-29T14:00:33.385Z","updated_at":"2025-12-14T23:03:53.377Z","avatar_url":"https://github.com/markkurossi.png","language":"Go","funding_links":[],"categories":["Software"],"sub_categories":["Frameworks"],"readme":"# mpc\n\nSecure Multi-Party Computation with Go. This project implements secure\ntwo-party computation with [Garbled circuit](https://en.wikipedia.org/wiki/Garbled_circuit) protocol. The main components are:\n - [garbled](apps/garbled/): **command-line program** for running MPCL programs\n - [compiler](compiler/): **Multi-Party Computation Language (MPCL)** compiler\n - [circuit](circuit/): **garbled circuit** parser, garbler, and evaluator\n - [ot](ot/): **oblivious transfer** library\n - [sha2pc](sha2pc/): **SHA256(XOR(a, b))** two-party protocol for two 32-byte inputs\n\n## Getting started\n\nThe easiest way to experiment with the system is to compile the\n[garbled](apps/garbled/) application and use it to evaluate MPCL\nprograms. The `garbled` application takes the following command line\noptions:\n\n - `-O`: optimization level (default 1 enabling all current optimizations).\n - `-circ`: compile inputs to circuit format.\n - `-cpuprofile`: write cpu profile to the specified file.\n - `-d`: enable diagnostics outputs.\n - `-dot`: generate Graphviz DOT output.\n - `-e`: specifies circuit _evaluator_ / _garbler_ mode. The circuit evaluator creates a TCP listener and waits for garblers to connect with computation.\n - `-format`: specifies circuit format for the `-circ` output file. Possible values are: `mpclc` (default), `bristol`.\n - `-i`: specifies comma-separated input values for the circuit.\n - `-memprofile`: write memory profile to the specified file.\n - `-ssa`: compile MPCL input to SSA assembly.\n - `-stream`: streaming mode.\n - `-v`: enabled verbose output.\n\nThe [examples](apps/garbled/examples/) directory contains various MPCL\nexample programs which can be executed with the `garbled`\napplication. For example, here's how you can run the [Yao's\nMillionaires'\nProblem](https://en.wikipedia.org/wiki/Yao%27s_Millionaires%27_Problem)\nwhich can be found from the\n[millionaire.mpcl](apps/garbled/examples/millionaire.mpcl) file:\n\n```go\npackage main\n\nfunc main(a, b int64) bool {\n    if a \u003e b {\n        return true\n    } else {\n        return false\n    }\n}\n```\n\nFirst, start the evaluator (these examples are run in the\n`apps/garbled` directory):\n\n```\n$ ./garbled -e -i 800000 examples/millionaire.mpcl\n - In1: a{1,0}i64:int64\n + In2: b{1,0}i64:int64\n - Out: %_{0,1}b1:bool1\n -  In: [800000]\nListening for connections at :8080\n```\n\nThe evaluator's input is 800000 and it is set to the circuit inputs\n`In2`. The evaluator is now waiting for garblers to connect to the TCP\nport `:8080`.\n\nNext, let's start the garbler:\n\n```\n$ ./garbled -i 750000 examples/millionaire.mpcl\n + In1: a{1,0}i64:int64\n - In2: b{1,0}i64:int64\n - Out: %_{0,1}b1:bool1\n -  In: [750000]\nResult[0]: false\n```\n\nThe garbler's input is 750000 and it is set to the circuit inputs\n`In1`. The garbler connects to the evaluator's TCP port and they run\nthe garbled circuit protocol. At the end, garbler (and evaluator)\nprint the result of the circuit, which is this case is single `bool`\nvalue `Result[0]`:\n\n```\nResult[0]: false\n```\n\nIn our example, the evaluator's argument In2 is bound to the MPCL\nprogram's `b int64` argument, and garbler's In1 to `a\nint64`. Therefore, the result of the computation is `false` because\nIn1=750000 \u003c= In2=800000. If we increase the garbler's input to 900000,\nwe see that the result is now `true` since the garbler's input is now\nbigger than the evaluator's input:\n\n```\n$ ./garbled -i 900000 examples/millionaire.mpcl\n + In1: a{1,0}i64:int64\n - In2: b{1,0}i64:int64\n - Out: %_{0,1}b1:bool1\n -  In: [900000]\nResult[0]: true\n```\n\n## Ed25519 Key Generation and Signature Computation\n\nThe [ed25519](apps/garbled/examples/ed25519/) directory contains\nEd25519 [key generation](apps/garbled/examples/ed25519/keygen.mpcl)\nand [signature computation](apps/garbled/examples/ed25519/sign.mpcl)\nexamples.\n\n### Key Generation\n\n```\n$ ./garbled -stream -e -v -i 0x784db0ec4ca0cf5338249e6a09139109366dca1fac2838e5f0e5a46f0e191bae,0xd0da45d3c99e756da831d1e7d696eae3fa9fe39d3b1b2618c7ff997d17777989b5cf415b114298c8b10bed0f0eff118e43ab606ab01143151dff89171307dffa,0x44bf09357e19b1f96f9cf6d9e7d25a0e8dd62d6e0d4bba2bec4c59983c7dc84d1486677b6d8837746cd948c881913c36faeaee08e8309afac58be4757a1c544e\n```\n\n```\n$ ./garbled -stream -v -i 0x57c0e59c20ac7d75ef7e3188fdd7f5876abee1cab394af8125acaca9760bb54c,0x76b42e6292f4a3dc339d208481abeb9a24e08127c7cd8dbde62abcddc0c0e6f7a0f740e756b44dae137f0e7ff8eae0ceb1a962c130fdcbe8cbee3e31ab55b8dc,0xeb83eb1f5203f5b752c96264a21ff4a27fa60cf2313f5f53c3fa96e0b52a2814b786e43a3af64b66291b5b29f432cb8d5a930e31f4e6f072a6d33b861b5b5f13 examples/ed25519/keygen.mpcl\n┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━┓\n┃ Op          ┃            Time ┃      % ┃ Xfer ┃\n┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━┩\n│ Init        │      2.039289ms │  0.00% │   0B │\n│ OT Init     │    248.443521ms │  0.27% │ 21kB │\n│ Peer Inputs │   10.330183787s │ 11.10% │  1MB │\n│ Eval        │ 1m22.462325965s │ 88.63% │ 14GB │\n│ Total       │ 1m33.042992562s │        │ 14GB │\n└─────────────┴─────────────────┴────────┴──────┘\nMax permanent wires: 52138674, cached circuits: 23\n#gates=824319227 (XOR=529672017 XNOR=28633983 AND=265892049 OR=116232 INV=4946 xor=558306000 !xor=266013227) #w=847060405\nResult[0]: 8ae64963506002e267a59665e9a2e6f9348cc159be53747894478e182ece9fcb\nResult[1]: 4ded80ae09692306c9659307f522f5dba1d96e48cde9f4f6e22fb340629db76aa2bee5867d009e008b6fb85902273acda8910c9a740a788f70c28ca0a3093835\nResult[2]: cd5c37f4497fd56e236aa858442b3ff90f7a6401ee2186ea18d074fe93d8f9d18b582fa47a1ee0f0a9083ddd9e262b8f3c642dfad68f667f87dddd4bec80aca3\n```\n\n### Signature Computation\n\n```\n$ ./garbled -stream -e -v -i 0x46eb82a021d88960fb13388b0e76ba13b84524ffe114d7f3a728b39efc185eeaa7137132182bab7504daf200d882b787ee8b9b1c9f41be9c38fb4e0ba1aff326\n```\n\n```\n$ ./garbled -stream -v -i 0x4d61726b6b7520526f737369203c6d747240696b692e66693e2068747470733a2f2f7777772e6d61726b6b75726f7373692e636f6d2f,0x5e768ad83640b43d93d6c26b34021d0a0cda6bf5eb962970554d7ab074e2f4cd49bc6fef2fa4dc2f763c1f70b751b7f03d398e8930d837130426454ea52d4449 examples/ed25519/sign.mpcl\n┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━┓\n┃ Op          ┃            Time ┃      % ┃  Xfer ┃\n┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━┩\n│ Init        │      1.303611ms │  0.00% │    0B │\n│ OT Init     │    131.270606ms │  0.15% │  16kB │\n│ Peer Inputs │    4.123998305s │  4.69% │ 667kB │\n│ Eval        │ 1m23.745891208s │ 95.16% │  15GB │\n│ Total       │  1m28.00246373s │        │  15GB │\n└─────────────┴─────────────────┴────────┴───────┘\nMax permanent wires: 53913890, cached circuits: 25\n#gates=830082709 (XOR=533261481 XNOR=28815787 AND=267491441 OR=494216 INV=19784 xor=562077268 !xor=268005441) #w=853799279\nResult[0]: b71a55aece64574bedd94729a9ca95a87b5fe0a587fecf50ff0238805132c1291e08cb871016cb4f3935bd45423626f61dc648a91affda3671b19d7b28e03505\n```\n\n# Multi-Party Computation Language (MPCL)\n\nThe multi-party computation language is heavily inspired by the Go\nprogramming language, however it is not using the Go's compiler or any\nother related components. The [compiler](compiler/) is an independent\nimplementation of the relevant parts of the Go syntax.\n\n## Builtin functions\n\nThe MPCL runtime defines the following builtin functions:\n\n - `copy(dst, src)`: copies the content of the array _src_ to\n   _dst_. The function returns the number of elements copied, which is\n   the minimum of len(src) and len(dst)\n - `len(value)`: returns the length of the value as integer:\n   - array: returns the number of array elements\n   - string: returns the number of bytes in the string\n - `make(type, size)`: creates an instance of the type _type_ with _size_ bits\n - `native(name, arg...)`: calls a builtin function _name_ with\n   arguments _arg..._. The _name_ can specify a circuit file (*.circ)\n   or one of the following builtin functions:\n   - `hamming(a, b uint)` computes the bitwise hamming distance between\n     argument values\n - `size(variable)`: returns the bit size of the argument _variable_\n - `wideMul(uintn, uintn) uint2n`: multiplies two n-bit unsigned\n   integer numbers and returns the 2n-bit unsigned integer result\n\n# TODO\n\n - [ ] setup CI running all the Go tests in each PR\n - [ ] [Graph](https://spidermonkey.dev/blog/2025/10/28/iongraph-web.html)\n - [ ] Foundation\n   - [x] Circuit \u0026 garbling:\n     - [x] Oblivious transfer extensions\n     - [ ] SSA variable liveness analysis must be optimized\n   - [ ] TLS for garbler-evaluator protocol\n   - [ ] BMR multi-party protocol\n - [ ] Compiler\n   - [ ] Check that `types.Rune` is used consistently.\n   - [ ] Incremental compiler\n     - [ ] Constant folding\n       - [ ] Implement using AST rewrite\n       - [ ] binary expressions\n       - [ ] if-blocks\n       - [ ] For-loop unrolling\n       - [ ] Function call and return\n     - [ ] peephole optimization\n       - [ ] SSA aliasing is 1:1 but `amov` has 2:1 relation\n       - [ ] variable liveness analysis for templates\n     - [ ] BitShift\n   - [x] `copy()` does not work on arrays which have been `make()`:ed\n   - [ ] `\u0026base[pos][i]` returns the address of the first element\n   - [ ] reading from `*[32]int32` returns invalid values\n   - [x] Pointer handling\n     - [ ] Cleanup pointer r-value handling\n     - [ ] Slices are passed by value instead of by reference\n     - [ ] Selecting struct members from struct pointer value\n - [ ] Streamer\n   - [ ] Uninitialized variables produce unspecified values in stream mode\n - [ ] Ed25519\n   - [x] Parsing Ed25519 MPCL files\n     - [ ] local variables in for-loop unrolling\n   - [ ] Compound init values must be zero-padded to full size\n\n## Circuit Optimization\n\nOptimizations from [stevengoldfeder.com](http://stevengoldfeder.com/projects/circuits/sha2circuit.html):\n\n| File            | No. ANDs        | No. XORs | No. INVs |         |\n| :-------------- | :-------------- | -------: | -------: | ------: |\n| Our circuit     | sha256Final.txt | 22,272   | 91,780   | 2,194   |\n| Bristol circuit | sha-256.txt     | 90,825   | 42,029   | 103,258 |\n\n# Benchmarks and tests\n\nPlease, see the [benchmarks.md](benchmarks.md) file for information\nabout various benchmarks.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkkurossi%2Fmpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkkurossi%2Fmpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkkurossi%2Fmpc/lists"}