Skip to content

Commit

Permalink
ZSL patch to prevent front-running attack (#587)
Browse files Browse the repository at this point in the history
  • Loading branch information
benediamond authored and fixanoid committed Dec 17, 2018
1 parent e39cc59 commit 8ba6534
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 27 deletions.
10 changes: 6 additions & 4 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,10 +521,12 @@ func (c *verifyUnshielding) Run(in []byte) ([]byte, error) {

var spend_nf [32]byte
var rt [32]byte
var addr [20]byte
copy(spend_nf[:], in[:32])
copy(rt[:], in[32:64])
noteValue := binary.BigEndian.Uint64(in[88:96])
proofSize := binary.BigEndian.Uint64(in[120:128]) // should be 584
copy(addr[:], in[76:96]) // type address === uint160
noteValue := binary.BigEndian.Uint64(in[120:128])
proofSize := binary.BigEndian.Uint64(in[152:160]) // should be 584

if proofSize != ZSL_PROOF_SIZE {
msg := fmt.Sprintf("ZSL error, proof must have size of %d bytes, not %d.\n", ZSL_PROOF_SIZE, proofSize)
Expand All @@ -533,9 +535,9 @@ func (c *verifyUnshielding) Run(in []byte) ([]byte, error) {
}

var proof [ZSL_PROOF_SIZE]byte
copy(proof[:], in[128:])
copy(proof[:], in[160:])

result := snark.VerifyUnshielding(proof, spend_nf, rt, noteValue)
result := snark.VerifyUnshielding(proof, spend_nf, rt, addr, noteValue)
var b byte
if result {
b = 1
Expand Down
46 changes: 35 additions & 11 deletions core/zsl/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ func computeSpendNullifier(rho []byte, sk [32]byte) []byte {
return h.Sum(nil)
}

// spend nullifier SHA256(0x01 || rho || sk || addr)
func computeSpendNullifierAuthenticated(rho []byte, sk [32]byte, addr [20]byte) []byte {
h := sha256.New()
h.Write([]byte{0x01})
h.Write(rho)
h.Write(sk[:])
h.Write(addr[:])
return h.Sum(nil)
}

// cm = SHA256(rho || pk || v) where v is in little endian byte order
func computeCommitment(rho [32]byte, pk [32]byte, v uint64) []byte {
vbuf := make([]byte, 8)
Expand Down Expand Up @@ -135,7 +145,7 @@ zsl.createUnshielding(rho, sk, value, treeIndex, authPath)
Verify with:
zsl.verifyUnshielding(proof, spend_nf, rt, value)
*/
func (api *PublicZSLAPI) CreateUnshielding(rho common.Hash, sk common.Hash, value float64, treeIndex float64, authPath []string) (map[string]interface{}, error) {
func (api *PublicZSLAPI) CreateUnshielding(rho common.Hash, sk common.Hash, addr common.Address, value float64, treeIndex float64, authPath []string) (map[string]interface{}, error) {
result := make(map[string]interface{})

// copy authentication path array into two dimensional array (as required by snark.ProveUnshielding())
Expand All @@ -154,9 +164,9 @@ func (api *PublicZSLAPI) CreateUnshielding(rho common.Hash, sk common.Hash, valu
}

snark.Init()
proof := snark.ProveUnshielding(rho, sk, uint64(value), uint64(treeIndex), authenticationPath)
proof := snark.ProveUnshielding(rho, sk, addr, uint64(value), uint64(treeIndex), authenticationPath)
send_nf := computeSendNullifier(rho[:])
spend_nf := computeSpendNullifier(rho[:], sk)
spend_nf := computeSpendNullifierAuthenticated(rho[:], sk, addr)
result["proof"] = "0x" + hex.EncodeToString(proof[:])
result["send_nf"] = common.BytesToHash(send_nf)
result["spend_nf"] = common.BytesToHash(spend_nf)
Expand Down Expand Up @@ -264,17 +274,17 @@ func (api *PublicZSLAPI) VerifyShielding(proofHex string, send_nf common.Hash, c
return result, nil
}

// geth: zsl.verifyShielding(proof, spend_nf, rt, value);
// geth: zsl.verifyUnshielding(proof, spend_nf, rt, addr, value);
// Javascript numbers are floats, there is no support for 64-bit integers.
func (api *PublicZSLAPI) VerifyUnshielding(proofHex string, spend_nf common.Hash, rt common.Hash, value float64) (bool, error) {
func (api *PublicZSLAPI) VerifyUnshielding(proofHex string, spend_nf common.Hash, rt common.Hash, addr common.Address, value float64) (bool, error) {

proof, err := getProofFromHex(proofHex)
if err != nil {
return false, err
}

snark.Init()
result := snark.VerifyUnshielding(proof, spend_nf, rt, uint64(value))
result := snark.VerifyUnshielding(proof, spend_nf, rt, addr, uint64(value))
return result, nil
}

Expand Down Expand Up @@ -337,7 +347,7 @@ func (api *PublicZSLAPI) DebugShielding() (bool, error) {
[32]byte{0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c},
2378237)
if !result {
return false, errors.New("proof was not valid as expected")
return false, errors.New("proof was not invalid as expected")
}

result = snark.VerifyShielding(proof,
Expand Down Expand Up @@ -367,6 +377,7 @@ func (api *PublicZSLAPI) DebugUnshielding() (bool, error) {
proof := snark.ProveUnshielding(
[32]byte{0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd},
[32]byte{0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff},
[20]byte{0xed, 0x9d, 0x02, 0xe3, 0x82, 0xb3, 0x48, 0x18, 0xe8, 0x8b, 0x88, 0xa3, 0x09, 0xc7, 0xfe, 0x71, 0xe6, 0x5f, 0x41, 0x9d},
2378237,
0,
[29][32]byte{
Expand Down Expand Up @@ -401,32 +412,45 @@ func (api *PublicZSLAPI) DebugUnshielding() (bool, error) {
{0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}})

result := snark.VerifyUnshielding(proof,
[32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a},
[32]byte{0x3a, 0x2c, 0xeb, 0xa3, 0x2e, 0xf0, 0x24, 0x56, 0xd5, 0x19, 0xf0, 0x66, 0xe6, 0xb6, 0xf8, 0xa2, 0x72, 0xb6, 0x88, 0x4a, 0xb5, 0x73, 0x61, 0x58, 0xc6, 0x30, 0x8e, 0x04, 0x38, 0x2a, 0x78, 0xaf},
[32]byte{0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03},
[20]byte{0xed, 0x9d, 0x02, 0xe3, 0x82, 0xb3, 0x48, 0x18, 0xe8, 0x8b, 0x88, 0xa3, 0x09, 0xc7, 0xfe, 0x71, 0xe6, 0x5f, 0x41, 0x9d},
2378237)
if !result {
return false, errors.New("proof was not valid as expected")
}

result = snark.VerifyUnshielding(proof,
[32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a},
[32]byte{0x3a, 0x2c, 0xeb, 0xa3, 0x2e, 0xf0, 0x24, 0x56, 0xd5, 0x19, 0xf0, 0x66, 0xe6, 0xb6, 0xf8, 0xa2, 0x72, 0xb6, 0x88, 0x4a, 0xb5, 0x73, 0x61, 0x58, 0xc6, 0x30, 0x8e, 0x04, 0x38, 0x2a, 0x78, 0xaf},
[32]byte{0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03},
[20]byte{0xed, 0x9d, 0x02, 0xe3, 0x82, 0xb3, 0x48, 0x18, 0xe8, 0x8b, 0x88, 0xa3, 0x09, 0xc7, 0xfe, 0x71, 0xe6, 0x5f, 0x41, 0x9d},
2378236)
if result {
return false, errors.New("proof was not invalid as expected")
}

result = snark.VerifyUnshielding(proof,
[32]byte{0x44, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a},
[32]byte{0x39, 0x2c, 0xeb, 0xa3, 0x2e, 0xf0, 0x24, 0x56, 0xd5, 0x19, 0xf0, 0x66, 0xe6, 0xb6, 0xf8, 0xa2, 0x72, 0xb6, 0x88, 0x4a, 0xb5, 0x73, 0x61, 0x58, 0xc6, 0x30, 0x8e, 0x04, 0x38, 0x2a, 0x78, 0xaf},
[32]byte{0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03},
[20]byte{0xed, 0x9d, 0x02, 0xe3, 0x82, 0xb3, 0x48, 0x18, 0xe8, 0x8b, 0x88, 0xa3, 0x09, 0xc7, 0xfe, 0x71, 0xe6, 0x5f, 0x41, 0x9d},
2378237)
if result {
return false, errors.New("proof was not invalid as expected")
}

result = snark.VerifyUnshielding(proof,
[32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a},
[32]byte{0x39, 0x2c, 0xeb, 0xa3, 0x2e, 0xf0, 0x24, 0x56, 0xd5, 0x19, 0xf0, 0x66, 0xe6, 0xb6, 0xf8, 0xa2, 0x72, 0xb6, 0x88, 0x4a, 0xb5, 0x73, 0x61, 0x58, 0xc6, 0x30, 0x8e, 0x04, 0x38, 0x2a, 0x78, 0xaf},
[32]byte{0x88, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03},
[20]byte{0xed, 0x9d, 0x02, 0xe3, 0x82, 0xb3, 0x48, 0x18, 0xe8, 0x8b, 0x88, 0xa3, 0x09, 0xc7, 0xfe, 0x71, 0xe6, 0x5f, 0x41, 0x9d},
2378237)
if result {
return false, errors.New("proof was not invalid as expected")
}

result = snark.VerifyUnshielding(proof,
[32]byte{0x3a, 0x2c, 0xeb, 0xa3, 0x2e, 0xf0, 0x24, 0x56, 0xd5, 0x19, 0xf0, 0x66, 0xe6, 0xb6, 0xf8, 0xa2, 0x72, 0xb6, 0x88, 0x4a, 0xb5, 0x73, 0x61, 0x58, 0xc6, 0x30, 0x8e, 0x04, 0x38, 0x2a, 0x78, 0xaf},
[32]byte{0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03},
[20]byte{0xec, 0x9d, 0x02, 0xe3, 0x82, 0xb3, 0x48, 0x18, 0xe8, 0x8b, 0x88, 0xa3, 0x09, 0xc7, 0xfe, 0x71, 0xe6, 0x5f, 0x41, 0x9d},
2378237)
if result {
return false, errors.New("proof was not invalid as expected")
Expand Down
4 changes: 2 additions & 2 deletions internal/web3ext/web3ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ web3._extend({
new web3._extend.Method({
name: 'createUnshielding',
call: 'zsl_createUnshielding',
params: 5
params: 6
}),
new web3._extend.Method({
name: 'createShieldedTransfer',
Expand All @@ -787,7 +787,7 @@ web3._extend({
new web3._extend.Method({
name: 'verifyUnshielding',
call: 'zsl_verifyUnshielding',
params: 4
params: 5
}),
new web3._extend.Method({
name: 'getNewAddress',
Expand Down
Loading

0 comments on commit 8ba6534

Please sign in to comment.