Skip to content
Merged
Show file tree
Hide file tree
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
24 changes: 3 additions & 21 deletions data/abi/abi_encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,6 @@ import (
"strings"
)

// bigIntToBytes casts non-negative big integer to byte slice with specific byte length
// DEPRECATED: THIS IS A WORKAROUND FOR `fillBytes` METHOD BEFORE GOLANG 1.15+
// SHOULD BE REMOVED AFTER WE MOVE TO HIGHER VERSION
func bigIntToBytes(x *big.Int, byteLen uint) ([]byte, error) {
if x.Cmp(big.NewInt(0)) < 0 {
return nil, fmt.Errorf("ABI: big Int To Bytes error: should pass in non-negative integer")
}
if uint(x.BitLen()) > byteLen*8 {
return nil, fmt.Errorf("ABI: big Int To Bytes error: integer byte length > given byte length")
}

buffer := make([]byte, byteLen)
intBytes := x.Bytes()
copy(buffer[int(byteLen)-len(intBytes):], intBytes)
return buffer, nil
}

// typeCastToTuple cast an array-like ABI type into an ABI tuple type.
func (t Type) typeCastToTuple(tupLen ...int) (Type, error) {
var childT []Type
Expand Down Expand Up @@ -187,14 +170,13 @@ func encodeInt(intValue interface{}, bitSize uint16) ([]byte, error) {
return nil, fmt.Errorf("passed in numeric value should be non negative")
}

castedBytes := make([]byte, bitSize/8)

if bigInt.Cmp(new(big.Int).Lsh(big.NewInt(1), uint(bitSize))) >= 0 {
return nil, fmt.Errorf("input value bit size %d > abi type bit size %d", bigInt.BitLen(), bitSize)
}

castedBytes, err := bigIntToBytes(bigInt, uint(bitSize/8))
if err != nil {
return nil, err
}
bigInt.FillBytes(castedBytes)
return castedBytes, nil
}

Expand Down
25 changes: 11 additions & 14 deletions data/abi/abi_encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ func TestEncodeValid(t *testing.T) {
randomInt, err := rand.Int(rand.Reader, upperLimit)
require.NoError(t, err, "cryptographic random int init fail")

expected, err := bigIntToBytes(randomInt, uint(intSize/8))
require.NoError(t, err, "big int to byte conversion error")
expected := make([]byte, intSize/8)
randomInt.FillBytes(expected)

uintEncode, err := uintType.Encode(randomInt)
require.NoError(t, err, "encoding from uint type fail")
Expand Down Expand Up @@ -122,9 +122,8 @@ func TestEncodeValid(t *testing.T) {
encodedUfixed, err := typeUfixed.Encode(randomInt)
require.NoError(t, err, "ufixed encode fail")

expected, err := bigIntToBytes(randomInt, uint(size/8))
require.NoError(t, err, "big int to byte conversion error")

expected := make([]byte, size/8)
randomInt.FillBytes(expected)
require.Equal(t, expected, encodedUfixed, "encode ufixed not match with expected")
}
// (2^[bitSize] - 1) / (10^[precision]) test
Expand All @@ -142,8 +141,8 @@ func TestEncodeValid(t *testing.T) {
randomAddrInt, err := rand.Int(rand.Reader, upperLimit)
require.NoError(t, err, "cryptographic random int init fail")

addrBytesExpected, err := bigIntToBytes(randomAddrInt, uint(addressByteSize))
require.NoError(t, err, "big int to byte conversion error")
addrBytesExpected := make([]byte, addressByteSize)
randomAddrInt.FillBytes(addrBytesExpected)

addrBytesActual, err := addressType.Encode(addrBytesExpected)
require.NoError(t, err, "address encode fail")
Expand Down Expand Up @@ -422,8 +421,8 @@ func TestDecodeValid(t *testing.T) {
randomAddrInt, err := rand.Int(rand.Reader, upperLimit)
require.NoError(t, err, "cryptographic random int init fail")

expected, err := bigIntToBytes(randomAddrInt, uint(addressByteSize))
require.NoError(t, err, "big int to byte conversion error")
expected := make([]byte, addressByteSize)
randomAddrInt.FillBytes(expected)

actual, err := addressType.Decode(expected)
require.NoError(t, err, "decoding address should not return error")
Expand Down Expand Up @@ -952,10 +951,8 @@ func addPrimitiveRandomValues(t *testing.T, pool *map[BaseType][]testUnit) {
for i := 0; i < addressTestCaseCount; i++ {
randAddrVal, err := rand.Int(rand.Reader, maxAddress)
require.NoError(t, err, "generate random value for address, should be no error")

addrBytes, err := bigIntToBytes(randAddrVal, uint(addressByteSize))
require.NoError(t, err, "big int to byte conversion error")

addrBytes := make([]byte, addressByteSize)
randAddrVal.FillBytes(addrBytes)
(*pool)[Address][i] = testUnit{serializedType: addressType.String(), value: addrBytes}
}
categorySelfRoundTripTest(t, (*pool)[Address])
Expand Down Expand Up @@ -1165,7 +1162,7 @@ func TestParseArgJSONtoByteSlice(t *testing.T) {

for i, test := range tests {
t.Run(fmt.Sprintf("index=%d", i), func(t *testing.T) {
applicationArgs := make([][]byte, 0)
applicationArgs := [][]byte{}
err := ParseArgJSONtoByteSlice(test.argTypes, test.jsonArgs, &applicationArgs)
require.NoError(t, err)
require.Equal(t, test.expectedAppArgs, applicationArgs)
Expand Down
9 changes: 3 additions & 6 deletions data/abi/abi_json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,14 @@ func TestRandomAddressEquality(t *testing.T) {

upperLimit := new(big.Int).Lsh(big.NewInt(1), addressByteSize<<3)
var addrBasics basics.Address
var addrABI = make([]byte, addressByteSize)
var addrABI []byte = make([]byte, addressByteSize)

for testCaseIndex := 0; testCaseIndex < addressTestCaseCount; testCaseIndex++ {
randomAddrInt, err := rand.Int(rand.Reader, upperLimit)
require.NoError(t, err, "cryptographic random int init fail")

expected, err := bigIntToBytes(randomAddrInt, uint(addressByteSize))
require.NoError(t, err, "big int to byte conversion error")

copy(addrABI[:], expected)
copy(addrBasics[:], expected)
randomAddrInt.FillBytes(addrBasics[:])
randomAddrInt.FillBytes(addrABI)

checkSumBasics := addrBasics.GetChecksum()
checkSumABI, err := addressCheckSum(addrABI)
Expand Down
66 changes: 5 additions & 61 deletions data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2917,72 +2917,16 @@ func opEd25519VerifyBare(cx *EvalContext) error {
return nil
}

// leadingZeros needs to be replaced by big.Int.FillBytes
func leadingZeros(size int, b *big.Int) ([]byte, error) {
data := b.Bytes()
if size < len(data) {
return nil, fmt.Errorf("insufficient buffer size: %d < %d", size, len(data))
byteLength := (b.BitLen() + 7) / 8
if size < byteLength {
return nil, fmt.Errorf("insufficient buffer size: %d < %d", size, byteLength)
}
if size == len(data) {
return data, nil
}

buf := make([]byte, size)
copy(buf[size-len(data):], data)
b.FillBytes(buf)
return buf, nil
}

// polynomial returns x³ - 3x + b.
//
// TODO: remove this when go-algorand is updated to go 1.15+
func polynomial(curve *elliptic.CurveParams, x *big.Int) *big.Int {
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)

threeX := new(big.Int).Lsh(x, 1)
threeX.Add(threeX, x)

x3.Sub(x3, threeX)
x3.Add(x3, curve.B)
x3.Mod(x3, curve.P)

return x3
}

// unmarshalCompressed converts a point, serialized by MarshalCompressed, into an x, y pair.
// It is an error if the point is not in compressed form or is not on the curve.
// On error, x = nil.
//
// TODO: remove this and replace usage with elliptic.UnmarshallCompressed when go-algorand is
// updated to go 1.15+
func unmarshalCompressed(curve elliptic.Curve, data []byte) (x, y *big.Int) {
byteLen := (curve.Params().BitSize + 7) / 8
if len(data) != 1+byteLen {
return nil, nil
}
if data[0] != 2 && data[0] != 3 { // compressed form
return nil, nil
}
p := curve.Params().P
x = new(big.Int).SetBytes(data[1:])
if x.Cmp(p) >= 0 {
return nil, nil
}
// y² = x³ - 3x + b
y = polynomial(curve.Params(), x)
y = y.ModSqrt(y, p)
if y == nil {
return nil, nil
}
if byte(y.Bit(0)) != data[0]&1 {
y.Neg(y).Mod(y, p)
}
if !curve.IsOnCurve(x, y) {
return nil, nil
}
return
}

var ecdsaVerifyCosts = map[byte]int{
byte(Secp256k1): 1700,
byte(Secp256r1): 2500,
Expand Down Expand Up @@ -3070,7 +3014,7 @@ func opEcdsaPkDecompress(cx *EvalContext) error {
return fmt.Errorf("invalid pubkey")
}
} else if fs.field == Secp256r1 {
x, y = unmarshalCompressed(elliptic.P256(), pubkey)
x, y = elliptic.UnmarshalCompressed(elliptic.P256(), pubkey)
Copy link
Contributor

@jannotti jannotti Apr 2, 2022

Choose a reason for hiding this comment

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

Should we retest the speed of decompress to reconsider opcode cost? Or was our implementation the same as this library function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The previous (un)marshalCompressed was copying the library implementation, so I felt like this should not change the speed.

if x == nil {
return fmt.Errorf("invalid compressed pubkey")
}
Expand Down
31 changes: 3 additions & 28 deletions data/transactions/logic/evalCrypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,23 +173,10 @@ ed25519verify_bare`, pkStr), v)
}
}

// bitIntFillBytes is a replacement for big.Int.FillBytes from future Go
func bitIntFillBytes(b *big.Int, buf []byte) []byte {
for i := range buf {
buf[i] = 0
}
bytes := b.Bytes()
if len(bytes) > len(buf) {
panic(fmt.Sprintf("bitIntFillBytes: has %d but got %d buffer", len(bytes), len(buf)))
}
copy(buf[len(buf)-len(bytes):], bytes)
return buf
}

func keyToByte(tb testing.TB, b *big.Int) []byte {
k := make([]byte, 32)
require.NotPanics(tb, func() {
k = bitIntFillBytes(b, k)
b.FillBytes(k)
})
return k
}
Expand Down Expand Up @@ -381,18 +368,6 @@ ecdsa_verify Secp256k1`, hex.EncodeToString(r), hex.EncodeToString(s), hex.Encod
require.True(t, pass)
}

// MarshalCompressed converts a point on the curve into the compressed form
// specified in section 4.3.6 of ANSI X9.62.
//
// TODO: replace with elliptic.MarshalCompressed when updating to go 1.15+
func marshalCompressed(curve elliptic.Curve, x, y *big.Int) []byte {
byteLen := (curve.Params().BitSize + 7) / 8
compressed := make([]byte, 1+byteLen)
compressed[0] = byte(y.Bit(0)) | 2
bitIntFillBytes(x, compressed[1:])
return compressed
}

func TestEcdsaWithSecp256r1(t *testing.T) {
if LogicVersion < fidoVersion {
return
Expand All @@ -403,7 +378,7 @@ func TestEcdsaWithSecp256r1(t *testing.T) {

key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
pk := marshalCompressed(elliptic.P256(), key.X, key.Y)
pk := elliptic.MarshalCompressed(elliptic.P256(), key.X, key.Y)
x := keyToByte(t, key.PublicKey.X)
y := keyToByte(t, key.PublicKey.Y)

Expand Down Expand Up @@ -676,7 +651,7 @@ func benchmarkEcdsaGenData(b *testing.B, curve EcdsaCurve) (data []benchmarkEcds
if curve == Secp256k1 {
data[i].pk = secp256k1.CompressPubkey(key.PublicKey.X, key.PublicKey.Y)
} else if curve == Secp256r1 {
data[i].pk = marshalCompressed(elliptic.P256(), key.PublicKey.X, key.PublicKey.Y)
data[i].pk = elliptic.MarshalCompressed(elliptic.P256(), key.PublicKey.X, key.PublicKey.Y)
}

d := []byte("testdata")
Expand Down