Skip to content
Closed
Changes from all commits
Commits
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
150 changes: 150 additions & 0 deletions data/transactions/logic/evalCrypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"fmt"
"math/big"
"strconv"
"strings"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -34,6 +35,7 @@ import (
"github.com/algorand/go-algorand/crypto/secp256k1"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/partitiontest"
)

Expand Down Expand Up @@ -173,6 +175,154 @@ ed25519verify_bare`, pkStr), v)
}
}

func TestEd25519verifyCompatValid(t *testing.T) {
partitiontest.PartitionTest(t)

// ed25519verify opcode uses prefix "ProgData" || program_hash in hex
// the following snippet produces: "50726f67446174610fefbfeb4749642b4e93f37098946ce11a63d6a8db82a416ff91321760212fac"
// for use below
/*
ops, err := AssembleStringWithVersion(`arg 0
arg 1
arg 2
ed25519verify`, AssemblerMaxVersion)
require.NoError(t, err)
h := crypto.HashObj(Program(ops.Program))
t.Log("program hash", hex.EncodeToString(h[:]))
t.Log("progdata", hex.EncodeToString([]byte(protocol.ProgramData)))
cat := append([]byte(protocol.ProgramData), h[:]...)
t.Log("progdata||program_hash", hex.EncodeToString(cat))
*/
// generated by github.com/p-steuer/eddsa-test
data, err := hex.DecodeString("cb68")
require.NoError(t, err)
vecs := [][3]string{
{
"50726f67446174610fefbfeb4749642b4e93f37098946ce11a63d6a8db82a416ff91321760212faccb68", // msg M
"5866666666666666666666666666666666666666666666666666666666666666", // pub A
"01000000000000000000000000000000000000000000000000000000000000006a889c732ac8ea1507a1547dcee1d74efc9113f9377216d8dfacc7fee5156504", // sig (R,S)
},
}
vecBytes := make([][3][]byte, len(vecs))
for i, tup3 := range vecs {
for j := range tup3 {
vecBytes[i][j], err = hex.DecodeString(vecs[i][j])
require.NoError(t, err)
}
}

for i, vec := range vecBytes {
t.Run(fmt.Sprintf("valid,vec=%v", vecs[i]), func(t *testing.T) {
// simple program that is only valid if EnableBatchVerification=true
ops, err := AssembleStringWithVersion(fmt.Sprintf(`arg 0
arg 1
arg 2
ed25519verify`), uint64(6))
require.NoError(t, err)
var txn transactions.SignedTxn
txn.Lsig.Logic = ops.Program
txn.Lsig.Args = [][]byte{data[:], vec[2], vec[1]}

// try with EnableBatchVerification = false
evalParams := defaultEvalParams(&txn)
evalParams.Proto.EnableBatchVerification = false
pass, err := EvalSignature(0, evalParams)
require.False(t, pass)
require.NoError(t, err)

// try with EnableBatchVerification = true
evalParams.Proto.EnableBatchVerification = true
pass, err = EvalSignature(0, evalParams)
require.True(t, pass)
require.NoError(t, err)
})
}
}

func TestEd25519verifyCompatPayment(t *testing.T) {
partitiontest.PartitionTest(t)

// generated by github.com/p-steuer/eddsa-test
data, err := hex.DecodeString("1dab")
require.NoError(t, err)
vecs := [][3]string{
{
"50726f6744617461f6691f135f7945d27ec1f87846d0694709e2ae67808ff4082a007a15754cb9a51dab", // msg M
"5866666666666666666666666666666666666666666666666666666666666666", // pub A
"0100000000000000000000000000000000000000000000000000000000000000095660bba17daf63dac3dc8c8600c55e25dd077032ff3c050bb0e9cdd0293b0e", // sig (R,S)
},
}
vecBytes := make([][3][]byte, len(vecs))
for i, tup3 := range vecs {
for j := range tup3 {
vecBytes[i][j], err = hex.DecodeString(vecs[i][j])
require.NoError(t, err)
}
}

for i, vec := range vecBytes {
t.Run(fmt.Sprintf("valid,vec=%v", vecs[i]), func(t *testing.T) {
// logic sig that lets you withdraw different amounts if EnableBatchVerification=true
/* (||
(&& (ed25519verify (arg 0) (arg 1) (arg 2))
(== (txn Amount) 1000000))
(&& (! (ed25519verify (arg 0) (arg 1) (arg 2)))
(== (txn Amount) 2000000))
)
*/
ops, err := AssembleStringWithVersion(`arg 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like to use testProg for assembling in tests. It checks the error for you and does not return it, it disassembles and reassembles to check equality giving us more tests for free, and does some logging if things don't work out.

arg 1
arg 2
ed25519verify
txn Amount
int 1000000
==
&&
arg 0
arg 1
arg 2
ed25519verify
!
txn Amount
int 2000000
==
&&
||`, uint64(6))
require.NoError(t, err)
h := crypto.HashObj(Program(ops.Program))
t.Log("program hash", hex.EncodeToString(h[:]))
t.Log("progdata", hex.EncodeToString([]byte(protocol.ProgramData)))
cat := append([]byte(protocol.ProgramData), h[:]...)
t.Log("progdata||program_hash", hex.EncodeToString(cat))

for _, tc := range []struct {
amount uint64
enableBatchVerification bool
valid bool
}{
{1000000, false, false}, // EnableBatchVerification = false, can't withdraw 1 algo
{2000000, false, true}, // EnableBatchVerification = false, withdraw 2 algos
{1000000, true, true}, // EnableBatchVerification = true, withdraw 1 algo
{2000000, true, false}, // EnableBatchVerification = true, can't withdraw 2 algos
} {
t.Run(fmt.Sprintf("%+v", tc), func(t *testing.T) {
var txn transactions.SignedTxn
txn.Lsig.Logic = ops.Program
txn.Lsig.Args = [][]byte{data[:], vec[2], vec[1]}
sb := strings.Builder{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see where you're putting sb in to trace. But you shouldn't have to anyway. defaultEvalParams inserts a string.Builder for you, so just change to evalParams.Trace.

txn.Txn.Amount = basics.MicroAlgos{Raw: tc.amount}
evalParams := defaultEvalParams(&txn)
evalParams.Proto.EnableBatchVerification = tc.enableBatchVerification
pass, err := EvalSignature(0, evalParams)
require.Equal(t, tc.valid, pass, "trace %s", sb.String())
t.Log(sb.String())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to Log the trace only if the test is about to fail, so the output is less cluttered when something else fails.

require.NoError(t, err)
})
}
})
}
}

// bitIntFillBytes is a replacement for big.Int.FillBytes from future Go
func bitIntFillBytes(b *big.Int, buf []byte) []byte {
for i := range buf {
Expand Down