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

supports larger sized input & output utxos #83

Merged
merged 28 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
870d6d5
adding batch circuits
Chengxuan Sep 24, 2024
a47c0c1
batch for fungible token with no encrypted values
Chengxuan Sep 25, 2024
ec1d4cb
supports batch for tokens with encrypted values
Chengxuan Sep 25, 2024
2a989b6
Merge branch 'main' of github.com:hyperledger-labs/zeto into more-inputs
Chengxuan Sep 25, 2024
7602dae
batch test for contracts
Chengxuan Sep 26, 2024
273cf81
return encrypted values for all outputs for batching
Chengxuan Sep 26, 2024
e057865
fix circuit tests due to changes
Chengxuan Sep 26, 2024
11b9a09
fixing gen command
Chengxuan Sep 26, 2024
20d302d
change ptau download folder for easy cleanup
Chengxuan Sep 26, 2024
c629bd7
fixing cloneable contract
Chengxuan Sep 26, 2024
30d6b1e
revert gas cost test changes
Chengxuan Sep 26, 2024
1f54faa
Merge branch 'main' of github.com:hyperledger-labs/zeto into more-inputs
Chengxuan Sep 27, 2024
1b4461f
fixing golang e2e
Chengxuan Sep 27, 2024
22a0cb8
adding a test for go-sdk for concurrency test
Chengxuan Sep 27, 2024
bea726d
Merge pull request #87 from hyperledger-labs/witness-concurrency
Chengxuan Sep 27, 2024
ccd8f7b
use an ephemeral private key to generate ECDH key
Chengxuan Sep 27, 2024
2254d92
fixing golang e2e
Chengxuan Sep 27, 2024
1e9addb
fixing gas cost test
Chengxuan Sep 29, 2024
6bb25ac
Merge pull request #88 from hyperledger-labs/random-ecdh-key
jimthematrix Sep 30, 2024
66f07b8
adding prettier
Chengxuan Oct 1, 2024
be4a593
lint all files
Chengxuan Oct 1, 2024
6879293
refactor and use double quotes
Chengxuan Oct 1, 2024
c32f725
add comments and rename variable
Chengxuan Oct 1, 2024
759c610
refactor for readability
Chengxuan Oct 1, 2024
63979e9
fixing encryption for output utxos
Chengxuan Oct 2, 2024
2b60412
comment out debug log
Chengxuan Oct 2, 2024
81dc745
fixing golang e2e
Chengxuan Oct 2, 2024
a79aa0f
disable result caching for golang e2e
Chengxuan Oct 2, 2024
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
3 changes: 1 addition & 2 deletions go-sdk/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ lint: ${LINT}
GOGC=20 $(LINT) run -v --timeout 5m
${LINT}:
$(VGO) install github.com/golangci/golangci-lint/cmd/[email protected]

go-mod-tidy: .ALWAYS
$(VGO) mod tidy
e2e: test
$(VGO) test -v ./integration-test
$(VGO) test -count=1 -v ./integration-test
.ALWAYS: ;
clean:
$(VGO) clean
Expand Down
92 changes: 88 additions & 4 deletions go-sdk/integration-test/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ func (s *E2ETestSuite) TestZeto_2_SuccessfulProving() {
outputCommitments := []*big.Int{output1, output2}

encryptionNonce := crypto.NewEncryptionNonce()
ephemeralKeypair := testutils.NewKeypair()

witnessInputs := map[string]interface{}{
"inputCommitments": inputCommitments,
Expand All @@ -228,6 +229,7 @@ func (s *E2ETestSuite) TestZeto_2_SuccessfulProving() {
"outputSalts": []*big.Int{salt3, salt4},
"outputOwnerPublicKeys": [][]*big.Int{{receiver.PublicKey.X, receiver.PublicKey.Y}, {sender.PublicKey.X, sender.PublicKey.Y}},
"encryptionNonce": encryptionNonce,
"ecdhPrivateKey": ephemeralKeypair.PrivateKey.Scalar().BigInt(),
}

startTime := time.Now()
Expand All @@ -242,21 +244,21 @@ func (s *E2ETestSuite) TestZeto_2_SuccessfulProving() {
assert.Equal(s.T(), 3, len(proof.Proof.A))
assert.Equal(s.T(), 3, len(proof.Proof.B))
assert.Equal(s.T(), 3, len(proof.Proof.C))
assert.Equal(s.T(), 9, len(proof.PubSignals))
assert.Equal(s.T(), 15, len(proof.PubSignals))

// the receiver would be able to get the encrypted values and salts
// from the transaction events
encryptedValues := make([]*big.Int, 4)
for i := 0; i < 4; i++ {
v, ok := new(big.Int).SetString(proof.PubSignals[i], 10)
v, ok := new(big.Int).SetString(proof.PubSignals[i+2], 10)
assert.True(s.T(), ok)
encryptedValues[i] = v
}

// the first two elements in the public signals are the encrypted value and salt
// for the first output. decrypt using the receiver's private key and compare with
// the UTXO hash
secret := crypto.GenerateECDHSharedSecret(receiver.PrivateKey, sender.PublicKey)
secret := crypto.GenerateECDHSharedSecret(receiver.PrivateKey, ephemeralKeypair.PublicKey)
decrypted, err := crypto.PoseidonDecrypt(encryptedValues, []*big.Int{secret.X, secret.Y}, encryptionNonce, 2)
assert.NoError(s.T(), err)
assert.Equal(s.T(), outputValues[0].String(), decrypted[0].String())
Expand Down Expand Up @@ -400,6 +402,7 @@ func (s *E2ETestSuite) TestZeto_4_SuccessfulProving() {
outputCommitments := []*big.Int{output1, output2}

encryptionNonce := crypto.NewEncryptionNonce()
ephemeralKeypair := testutils.NewKeypair()

proof1Siblings := make([]*big.Int, len(circomProof1.Siblings)-1)
for i, s := range circomProof1.Siblings[0 : len(circomProof1.Siblings)-1] {
Expand All @@ -423,6 +426,7 @@ func (s *E2ETestSuite) TestZeto_4_SuccessfulProving() {
"outputSalts": []*big.Int{salt3, salt4},
"outputOwnerPublicKeys": [][]*big.Int{{receiver.PublicKey.X, receiver.PublicKey.Y}, {sender.PublicKey.X, sender.PublicKey.Y}},
"encryptionNonce": encryptionNonce,
"ecdhPrivateKey": ephemeralKeypair.PrivateKey.Scalar().BigInt(),
}

startTime := time.Now()
Expand All @@ -437,7 +441,7 @@ func (s *E2ETestSuite) TestZeto_4_SuccessfulProving() {
assert.Equal(s.T(), 3, len(proof.Proof.A))
assert.Equal(s.T(), 3, len(proof.Proof.B))
assert.Equal(s.T(), 3, len(proof.Proof.C))
assert.Equal(s.T(), 12, len(proof.PubSignals))
assert.Equal(s.T(), 18, len(proof.PubSignals))
}

func (s *E2ETestSuite) TestZeto_5_SuccessfulProving() {
Expand Down Expand Up @@ -496,6 +500,86 @@ func (s *E2ETestSuite) TestZeto_5_SuccessfulProving() {
assert.Equal(s.T(), 3, len(proof.Proof.B))
assert.Equal(s.T(), 3, len(proof.Proof.C))
assert.Equal(s.T(), 2, len(proof.PubSignals))

}

func (s *E2ETestSuite) TestZeto_5_SuccessfulProvingWithConcurrency() {
concurrency := 10
resultChan := make(chan struct{}, concurrency)

for i := 0; i < concurrency; i++ {
index := i
go func() {
defer func() {
resultChan <- struct{}{}
}()
calc, provingKey, err := loadCircuit("nf_anon")
Chengxuan marked this conversation as resolved.
Show resolved Hide resolved
assert.NoError(s.T(), err)
assert.NotNil(s.T(), calc)

sender := testutils.NewKeypair()
receiver := testutils.NewKeypair()

tokenId := big.NewInt(int64(index + 1)) // ensure different token uris for each run
tokenUri, err := utxo.HashTokenUri("https://example.com/token/" + tokenId.String())
assert.NoError(s.T(), err)

salt1 := crypto.NewSalt()
input1, err := poseidon.Hash([]*big.Int{tokenId, tokenUri, salt1, sender.PublicKey.X, sender.PublicKey.Y})
assert.NoError(s.T(), err)

salt3 := crypto.NewSalt()
output1, err := poseidon.Hash([]*big.Int{tokenId, tokenUri, salt3, receiver.PublicKey.X, receiver.PublicKey.Y})
assert.NoError(s.T(), err)

witnessInputs := map[string]interface{}{
"tokenIds": []*big.Int{tokenId},
"tokenUris": []*big.Int{tokenUri},
"inputCommitments": []*big.Int{input1},
"inputSalts": []*big.Int{salt1},
"inputOwnerPrivateKey": sender.PrivateKeyBigInt,
"outputCommitments": []*big.Int{output1},
"outputSalts": []*big.Int{salt3},
"outputOwnerPublicKeys": [][]*big.Int{{receiver.PublicKey.X, receiver.PublicKey.Y}},
}
// calculate the witness object for checking correctness
witness, err := calc.CalculateWitness(witnessInputs, true)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), witness)

assert.Equal(s.T(), 0, witness[0].Cmp(big.NewInt(1)))
assert.Equal(s.T(), 0, witness[1].Cmp(input1))
assert.Equal(s.T(), 0, witness[2].Cmp(output1))
assert.Equal(s.T(), 0, witness[3].Cmp(tokenId))
assert.Equal(s.T(), 0, witness[4].Cmp(tokenUri))

// generate the witness binary to feed into the prover
startTime := time.Now()
witnessBin, err := calc.CalculateWTNSBin(witnessInputs, true)
assert.NoError(s.T(), err)
assert.NotNil(s.T(), witnessBin)

proof, err := prover.Groth16Prover(provingKey, witnessBin)
Chengxuan marked this conversation as resolved.
Show resolved Hide resolved
elapsedTime := time.Since(startTime)
fmt.Printf("Proving time: %s\n", elapsedTime)
fmt.Printf("token uri from witness: %s\n", witness[3])
assert.NoError(s.T(), err)
assert.Equal(s.T(), 3, len(proof.Proof.A))
assert.Equal(s.T(), 3, len(proof.Proof.B))
assert.Equal(s.T(), 3, len(proof.Proof.C))
assert.Equal(s.T(), 2, len(proof.PubSignals))

}()
}
count := 0
for {
<-resultChan
count++
if count == concurrency {
break
}
}

}

func (s *E2ETestSuite) TestZeto_6_SuccessfulProving() {
Expand Down
8 changes: 7 additions & 1 deletion solidity/contracts/factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ contract ZetoTokenFactory is Ownable {
address depositVerifier;
address withdrawVerifier;
address verifier;
address batchVerifier;
}

event ZetoTokenDeployed(address indexed zetoToken);
Expand Down Expand Up @@ -74,6 +75,10 @@ contract ZetoTokenFactory is Ownable {
args.withdrawVerifier != address(0),
"Factory: withdrawVerifier address is required"
);
require(
args.batchVerifier != address(0),
"Factory: batchVerifier address is required"
);
address instance = Clones.clone(args.implementation);
require(
instance != address(0),
Expand All @@ -83,7 +88,8 @@ contract ZetoTokenFactory is Ownable {
initialOwner,
args.verifier,
args.depositVerifier,
args.withdrawVerifier
args.withdrawVerifier,
args.batchVerifier
);
emit ZetoTokenDeployed(instance);
return instance;
Expand Down
18 changes: 18 additions & 0 deletions solidity/contracts/lib/common.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ library Commonlib {
uint[2] pC;
}

function padUintArray(
uint256[] memory arr,
uint256 targetLength,
uint256 padValue
) internal pure returns (uint256[] memory) {
if (arr.length == targetLength) {
return arr;
}
uint256[] memory paddedArray = new uint256[](targetLength);
for (uint256 i = 0; i < arr.length; i++) {
paddedArray[i] = arr[i];
}
for (uint256 i = arr.length; i < targetLength; i++) {
paddedArray[i] = padValue;
}
return paddedArray;
}

function getProofHash(
Proof calldata proof
) internal pure returns (bytes32) {
Expand Down
1 change: 1 addition & 0 deletions solidity/contracts/lib/interfaces/izeto_encrypted.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface IZetoEncrypted is IZetoBase {
uint256[] inputs,
uint256[] outputs,
uint256 encryptionNonce,
uint256[2] ecdhPublicKey,
uint256[] encryptedValues,
address indexed submitter,
bytes data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface IZetoFungibleInitializable {
address initialOwner,
address _depositVerifier,
address _withdrawVerifier,
address _verifier
address _verifier,
address _batchVerifier
) external;
}
Loading
Loading