Skip to content

Commit

Permalink
fix: cleanup, correct errors & typos, add assets
Browse files Browse the repository at this point in the history
  • Loading branch information
socathie committed May 10, 2023
1 parent 20c4ac3 commit 167259d
Show file tree
Hide file tree
Showing 13 changed files with 16,953 additions and 53 deletions.
72 changes: 19 additions & 53 deletions EIPS/eip-7007.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,29 @@
---
eip: 7007
title: zkML AIGC-NFTs
description: A standard ERC721 extension interface for zkML based AIGC-NFTs.
description: An ERC-721 extension interface for zkML based AIGC-NFTs.
author: Cathie So (@socathie), Xiaohang Yu (@xhyumiracle), Huaizhe Xu (@HuaizheXu), Kartin Wang (@kartinW)
discussions-to: <URL>
discussions-to: https://ethereum-magicians.org/t/eip-7007-zkml-aigc-nfts-a-standard-erc721-extension-interface-for-zkml-based-aigc-nfts/14216
status: Draft
type: Standards Track
category: ERC # Only required for Standards Track. Otherwise, remove this field.
category: ERC
created: 2023-05-10
requires: 721 # Only required when you reference an EIP in the `Specification` section. Otherwise, remove this field.
requires: 165, 721
---

<!--
READ EIP-1 (https://eips.ethereum.org/EIPS/eip-1) BEFORE USING THIS TEMPLATE!
This is the suggested template for new EIPs. After you have filled in the requisite fields, please delete these comments.
Note that an EIP number will be assigned by an editor. When opening a pull request to submit your EIP, please use an abbreviated title in the filename, `eip-draft_title_abbrev.md`.
The title should be 44 characters or less. It should not repeat the EIP number in title, irrespective of the category.
TODO: Remove this comment before submitting
-->

## Abstract

<!--
The Abstract is a multi-sentence (short paragraph) technical summary. This should be a very terse and human-readable version of the specification section. Someone should be able to read only the abstract to get the gist of what this specification does.
TODO: Remove this comment before submitting
-->
The zkML AIGC-NFTs standard is an extension of the ERC721 token standard for AI Generated Content. It proposes a set of interfaces for basic interactions and enumerable interactions for AIGC-NFTs. The standard includes a new mint event and a JSON schema for AIGC-NFT metadata. Additionally, it incorporates zkML capabilities to enable verification of AIGC-NFT ownership. In this standard, the tokenId is indexed by the prompt.

## Motivation

<!--
This section is optional.
The motivation section should include a description of any nontrivial problems the EIP solves. It should not describe how the EIP solves those problems, unless it is not immediately obvious. It should not describe why the EIP should be made into a standard, unless it is not immediately obvious.
With a few exceptions, external links are not allowed. If you feel that a particular resource would demonstrate a compelling case for your EIP, then save it as a printer-friendly PDF, put it in the assets folder, and link to that copy.
TODO: Remove this comment before submitting
-->
The zkML AIGC-NFTs standard is an extension of the [ERC-721](./eip-721.md) token standard for AI Generated Content. It proposes a set of interfaces for basic interactions and enumerable interactions for AIGC-NFTs. The standard includes a new mint event and a JSON schema for AIGC-NFT metadata. Additionally, it incorporates zkML capabilities to enable verification of AIGC-NFT ownership. In this standard, the `tokenId` is indexed by the `prompt`.

## Specification

<!--
The Specification section should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (besu, erigon, ethereumjs, go-ethereum, nethermind, or others).
It is recommended to follow RFC 2119 and RFC 8170. Do not remove the key word definitions if RFC 2119 and RFC 8170 are followed.
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

TODO: Remove this comment before submitting
-->
**Every compliant contract must implement the [ERC-7007](./eip-7007.md), [ERC-721](./eip-721.md), and [ERC-165](./eip-165.md) interfaces.**

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

### Interfaces
**Every ERC-7007 compliant contract must implement the `ERC7007`, `ERC721` and `ERC165` interfaces**
The zkML AIGC-NFTs standard includes the following interfaces:

ERC7007: Defines a mint event and a mint function for minting AIGC-NFTs. It also includes a verify function to check the validity of a combination of prompt and proof using zkML techniques.
ERC-7007: Defines a mint event and a mint function for minting AIGC-NFTs. It also includes a verify function to check the validity of a combination of prompt and proof using zkML techniques.

```solidity
pragma solidity ^0.8.18;
Expand Down Expand Up @@ -108,7 +71,9 @@ interface IERC7007 is IERC165 {
}
```

ERC7007Enumerable: The **enumeration extension** is OPTIONAL for ERC-7007 smart contracts. This allows your contract to publish its full list of mapping between `tokenId` and `prompt` and make them discoverable.
Optional Extension: Enumerable

The **enumeration extension** is OPTIONAL for [ERC-7007](./eip-7007.md) smart contracts. This allows your contract to publish its full list of mapping between `tokenId` and `prompt` and make them discoverable.

```solidity
pragma solidity ^0.8.18;
Expand All @@ -129,7 +94,8 @@ interface IERC7007Enumerable is IERC7007 {
}
```

This is the "ERC721 Metadata JSON Schema" referenced by the optional ERC721Metadata extension.
ERC-7007 Metadata JSON Schema for reference

```json
{
"title": "AIGC Metadata",
Expand Down Expand Up @@ -164,24 +130,24 @@ This is the "ERC721 Metadata JSON Schema" referenced by the optional ERC721Metad
}
```


## Rationale

The zkML AIGC-NFTs standard aims to extend the existing ERC721 token standard to accommodate the unique requirements of AI Generated Content NFTs representing models in a collection. This standard provides interfaces to use zkML to verify whether or not the AIGC data for a NFT is generated from a certain ML model with certain input (prompt). The proposed interfaces allow for additional functionality related to minting, verifying, and enumerating AIGC-NFTs. Additionally, the metadata schema provides a structured format for storing information related to AIGC-NFTs, such as the prompt used to generate the content and the proof of ownership.
The zkML AIGC-NFTs standard aims to extend the existing [ERC-721](./eip-721.md) token standard to accommodate the unique requirements of AI Generated Content NFTs representing models in a collection. This standard provides interfaces to use zkML to verify whether or not the AIGC data for an NFT is generated from a certain ML model with certain input (prompt). The proposed interfaces allow for additional functionality related to minting, verifying, and enumerating AIGC-NFTs. Additionally, the metadata schema provides a structured format for storing information related to AIGC-NFTs, such as the prompt used to generate the content and the proof of ownership.

With this standard, model owner can publish their trained model and its ZKP verifier to Ethereum. Any user can claim an input (prompt) and publish the inference task, any node that maintains the model and the proving circuit can do the inference and proving, then submitting the output of inference and the ZK proof for the inference trace into the verifier that is deployed by the model owner. The user that initiates the inference task will own the output for the inference of that model and input (prompt).
With this standard, model owners can publish their trained model and its ZKP verifier to Ethereum. Any user can claim an input (prompt) and publish the inference task, any node that maintains the model and the proving circuit can perform the inference and proving, then submit the output of inference and the ZK proof for the inference trace into the verifier that is deployed by the model owner. The user that initiates the inference task will own the output for the inference of that model and input (prompt).

## Backwards Compatibility

This standard is backwards compatible with the ERC721 standard as it extends the existing functionality with new interfaces.
This standard is backward compatible with the [ERC-721](./eip-721.md) as it extends the existing functionality with new interfaces.

## Test Cases

The provided Solidity code includes a sample implementation of the AIGC-NFT interfaces as a contract named AIGC_Test. This contract can be used to test the functionality of the proposed interfaces and metadata schema.
The reference implementation includes sample implementations of the [ERC-7007](./eip-7007.md) interfaces under `contracts/` and corresponding unit tests under `test/`. This repo can be used to test the functionality of the proposed interfaces and metadata schema.

## Reference Implementation

https://github.com/AIGC-NFT/implementation
* [ERC-7007](../assets/eip-7007/contracts/ERC7007.sol)
* [ERC-7007 Enumerable Extension](../assets/eip-7007/contracts/ERC7007Enumerable.sol)

## Security Considerations

Expand Down
11 changes: 11 additions & 0 deletions assets/eip-7007/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
node_modules
.env
coverage
coverage.json
typechain
typechain-types

# Hardhat files
cache
artifacts

55 changes: 55 additions & 0 deletions assets/eip-7007/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ERC-7007 Reference Implementation

This is a WIP implementation of ERC-7007 based on the discussions in the [EIP-7007 issue thread](https://github.com/ethereum/EIPs/issues/7007).

## Setup
Run `npm install` in the root directory.

## Testing
Try running some of the following tasks:

```shell
npx hardhat help
npx hardhat test
REPORT_GAS=true npx hardhat test
```

## Metadata Standard

```json
{
"title": "AIGC Metadata",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Identifies the asset to which this NFT represents"
},
"description": {
"type": "string",
"description": "Describes the asset to which this NFT represents"
},
"image": {
"type": "string",
"description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive."
},

"prompt": {
"type": "string",
"description": "Identifies the prompt from which this AIGC NFT generated"
},
"seed": {
"type": "uint256",
"description": "Identifies the seed from which this AIGC NFT generated"
},
"aigc_type": {
"type": "string",
"description": "image/video/audio..."
},
"aigc_data": {
"type": "string",
"description": "A URI pointing to a resource with mime type image/* representing the asset to which this AIGC NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive."
}
}
}
```
79 changes: 79 additions & 0 deletions assets/eip-7007/contracts/ERC7007.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "./IERC7007.sol";
import "./IVerifier.sol";

/**
* @dev Implementation of the {IERC7007} interface.
*/
contract ERC7007 is ERC165, IERC7007, ERC721URIStorage {
address public immutable verifier;

/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
constructor(
string memory name_,
string memory symbol_,
address verifier_
) ERC721(name_, symbol_) {
verifier = verifier_;
}

/**
* @dev See {IERC7007-mint}.
*/
function mint(
bytes calldata prompt,
bytes calldata aigcData,
string calldata uri,
bytes calldata proof
) public virtual override returns (uint256 tokenId) {
require(verify(prompt, aigcData, proof), "ERC7007: invalid proof");
tokenId = uint256(keccak256(prompt));
_safeMint(msg.sender, tokenId);
string memory tokenUri = string(
abi.encodePacked(
"{",
uri,
', "prompt": "',
string(prompt),
'", "aigc_data": "',
string(aigcData),
'"}'
)
);
_setTokenURI(tokenId, tokenUri);
emit Mint(tokenId, prompt, aigcData, uri, proof);
}

/**
* @dev See {IERC7007-verify}.
*/
function verify(
bytes calldata prompt,
bytes calldata aigcData,
bytes calldata proof
) public view virtual override returns (bool success) {
return
IVerifier(verifier).verifyProof(
proof,
abi.encodePacked(prompt, aigcData)
);
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC165, ERC721, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
}
54 changes: 54 additions & 0 deletions assets/eip-7007/contracts/ERC7007Enumerable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "./ERC7007.sol";
import "./IERC7007Enumerable.sol";

/**
* @dev Implementation of the {IERC7007Enumerable} interface.
*/
abstract contract ERC7007Enumerable is ERC7007, IERC7007Enumerable {
/**
* @dev See {IERC7007Enumerable-tokenId}.
*/
mapping(uint256 => string) public prompt;


/**
* @dev See {IERC7007Enumerable-prompt}.
*/
mapping(bytes => uint256) public tokenId;

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override(IERC165, ERC7007) returns (bool) {
return
interfaceId == type(IERC7007Enumerable).interfaceId ||
super.supportsInterface(interfaceId);
}

/**
* @dev See {IERC7007-mint}.
*/
function mint(
bytes calldata prompt_,
bytes calldata aigcData,
string calldata uri,
bytes calldata proof
) public virtual override(ERC7007, IERC7007) returns (uint256 tokenId_) {
tokenId_ = ERC7007.mint(prompt_, aigcData, uri, proof);
prompt[tokenId_] = string(prompt_);
tokenId[prompt_] = tokenId_;
}
}

contract MockERC7007Enumerable is ERC7007Enumerable {
constructor(
string memory name_,
string memory symbol_,
address verifier_
) ERC7007(name_, symbol_, verifier_) {}
}
46 changes: 46 additions & 0 deletions assets/eip-7007/contracts/IERC7007.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
* @dev Required interface of an ERC7007 compliant contract.
*/
interface IERC7007 is IERC165 {
/**
* @dev Emitted when `tokenId` token is minted.
*/
event Mint(
uint256 indexed tokenId,
bytes indexed prompt,
bytes indexed aigcData,
string uri,
bytes proof
);

/**
* @dev Mint token at `tokenId` given `prompt`, `aigcData`, `uri` and `proof`.
*
* Requirements:
* - `tokenId` must not exist.'
* - verify(`prompt`, `aigcData`, `proof`) must return true.
*
* Optional:
* - `proof` should not include `aigcData` to save gas.
*/
function mint(
bytes calldata prompt,
bytes calldata aigcData,
string calldata uri,
bytes calldata proof
) external returns (uint256 tokenId);

/**
* @dev Verify the `prompt`, `aigcData` and `proof`.
*/
function verify(
bytes calldata prompt,
bytes calldata aigcData,
bytes calldata proof
) external view returns (bool success);
}
19 changes: 19 additions & 0 deletions assets/eip-7007/contracts/IERC7007Enumerable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "./IERC7007.sol";

/**
* @title ERC7007 Token Standard, optional enumeration extension
*/
interface IERC7007Enumerable is IERC7007 {
/**
* @dev Returns the token ID given `prompt`.
*/
function tokenId(bytes calldata prompt) external view returns (uint256);

/**
* @dev Returns the prompt given `tokenId`.
*/
function prompt(uint256 tokenId) external view returns (string calldata);
}
Loading

0 comments on commit 167259d

Please sign in to comment.