From 594e8e42349219f70d6804bbed7f31fbf267802c Mon Sep 17 00:00:00 2001 From: Jacob Daitzman Date: Thu, 30 Jun 2022 14:41:49 -0400 Subject: [PATCH] Add `Ed25519Verify_Bare` (#426) * Add ed25519verify_bare * Fix typos in Ed25519 docstrings (#2) * Add crypto doc for Ed25519Verify_Bare Co-authored-by: Michael Diamant --- docs/crypto.rst | 3 ++- pyteal/__init__.pyi | 1 + pyteal/ast/__init__.py | 9 ++++++++- pyteal/ast/ternaryexpr.py | 22 +++++++++++++++++++-- pyteal/ast/ternaryexpr_test.py | 36 ++++++++++++++++++++++++++++++++++ pyteal/ir/ops.py | 1 + 6 files changed, 68 insertions(+), 4 deletions(-) diff --git a/docs/crypto.rst b/docs/crypto.rst index 2ae4055b1..6a80b2567 100644 --- a/docs/crypto.rst +++ b/docs/crypto.rst @@ -17,7 +17,8 @@ Operator Cost Description :code:`Sha3_256(e)` `130` `SHA3-256` hash function, produces 32 bytes :code:`Keccak256(e)` `130` `Keccak-256` hash funciton, produces 32 bytes :code:`Sha512_256(e)` `45` `SHA-512/256` hash function, produces 32 bytes -:code:`Ed25519Verify(d, s, p)` `1900`\* `1` if :code:`s` is the signature of :code:`d` signed by the private key corresponding to the public key :code:`p`, else `0` +:code:`Ed25519Verify(d, s, p)` `1900`\* `1` if :code:`s` is the signature of the concatenation :code:`("ProgData" + hash_of_current_program + d)` signed by the private key corresponding to the public key :code:`p`, else `0` +:code:`Ed25519Verify_Bare(d, s, p)` `1900` `1` if :code:`s` is the signature of :code:`d` signed by the private key corresponding to the public key :code:`p`, else `0` :code:`EcdsaVerify(c, d, r, s, pk)` `1700` `1` if :code:`(r, s)` is the signature of :code:`d` by private key corresponding to public key :code:`pk`, else 0 :code:`EcdsaDecompress(c, short_pk)` `650` produces the decompressed public key associated with the compressed public key :code:`short_pk` :code:`EcdsaRecover(c, d, id, r, s)` `2000` produces the public key associated with the signature :code:`(r, s)` and recovery id :code:`id` diff --git a/pyteal/__init__.pyi b/pyteal/__init__.pyi index 79545ec99..4e2e3b65b 100644 --- a/pyteal/__init__.pyi +++ b/pyteal/__init__.pyi @@ -78,6 +78,7 @@ __all__ = [ "EcdsaRecover", "EcdsaVerify", "Ed25519Verify", + "Ed25519Verify_Bare", "EnumInt", "Eq", "Err", diff --git a/pyteal/ast/__init__.py b/pyteal/ast/__init__.py index 61d3254d3..145e7f2f3 100644 --- a/pyteal/ast/__init__.py +++ b/pyteal/ast/__init__.py @@ -103,7 +103,13 @@ from pyteal.ast.base64decode import Base64Decode # ternary ops -from pyteal.ast.ternaryexpr import Divw, Ed25519Verify, SetBit, SetByte +from pyteal.ast.ternaryexpr import ( + Divw, + Ed25519Verify, + Ed25519Verify_Bare, + SetBit, + SetByte, +) from pyteal.ast.substring import Substring, Extract, Suffix from pyteal.ast.replace import Replace from pyteal.ast.jsonref import JsonRef @@ -228,6 +234,7 @@ "GetBit", "GetByte", "Ed25519Verify", + "Ed25519Verify_Bare", "Substring", "Extract", "Suffix", diff --git a/pyteal/ast/ternaryexpr.py b/pyteal/ast/ternaryexpr.py index b329165de..ad2c36bd6 100644 --- a/pyteal/ast/ternaryexpr.py +++ b/pyteal/ast/ternaryexpr.py @@ -62,9 +62,9 @@ def Ed25519Verify(data: Expr, sig: Expr, key: Expr) -> TernaryExpr: """Verify the ed25519 signature of the concatenation ("ProgData" + hash_of_current_program + data). Args: - data: The data signed by the public key. Must evalutes to bytes. + data: The data signed by the public key. Must evaluate to bytes. sig: The proposed 64-byte signature of the concatenation ("ProgData" + hash_of_current_program + data). - Must evalute to bytes. + Must evaluate to bytes. key: The 32 byte public key that produced the signature. Must evaluate to bytes. """ return TernaryExpr( @@ -77,6 +77,24 @@ def Ed25519Verify(data: Expr, sig: Expr, key: Expr) -> TernaryExpr: ) +def Ed25519Verify_Bare(data: Expr, sig: Expr, key: Expr) -> TernaryExpr: + """Verify the ed25519 signature of the data against the public key. + + Args: + data: The data signed by the public key. Must evaluate to bytes. + sig: The proposed 64-byte signature of the data. Must evaluate to bytes. + key: The 32 byte public key that produced the signature. Must evaluate to bytes. + """ + return TernaryExpr( + Op.ed25519verify_bare, + (TealType.bytes, TealType.bytes, TealType.bytes), + TealType.uint64, + data, + sig, + key, + ) + + def SetBit(value: Expr, index: Expr, newBitValue: Expr) -> TernaryExpr: """Set the bit value of an expression at a specific index. diff --git a/pyteal/ast/ternaryexpr_test.py b/pyteal/ast/ternaryexpr_test.py index 996c58635..51a01958a 100644 --- a/pyteal/ast/ternaryexpr_test.py +++ b/pyteal/ast/ternaryexpr_test.py @@ -7,6 +7,7 @@ teal4Options = pt.CompileOptions(version=4) teal5Options = pt.CompileOptions(version=5) teal6Options = pt.CompileOptions(version=6) +teal7Options = pt.CompileOptions(version=7) def test_ed25519verify(): @@ -41,6 +42,41 @@ def test_ed25519verify_invalid(): pt.Ed25519Verify(pt.Bytes("data"), pt.Bytes("sig"), pt.Int(0)) +def test_ed25519verify_bare(): + args = [pt.Bytes("data"), pt.Bytes("sig"), pt.Bytes("key")] + expr = pt.Ed25519Verify_Bare(args[0], args[1], args[2]) + assert expr.type_of() == pt.TealType.uint64 + + expected = pt.TealSimpleBlock( + [ + pt.TealOp(args[0], pt.Op.byte, '"data"'), + pt.TealOp(args[1], pt.Op.byte, '"sig"'), + pt.TealOp(args[2], pt.Op.byte, '"key"'), + pt.TealOp(expr, pt.Op.ed25519verify_bare), + ] + ) + + actual, _ = expr.__teal__(teal7Options) + actual.addIncoming() + actual = pt.TealBlock.NormalizeBlocks(actual) + + assert actual == expected + + with pytest.raises(pt.TealInputError): + expr.__teal__(teal6Options) + + +def test_ed25519verify_bare_invalid(): + with pytest.raises(pt.TealTypeError): + pt.Ed25519Verify_Bare(pt.Int(0), pt.Bytes("sig"), pt.Bytes("key")) + + with pytest.raises(pt.TealTypeError): + pt.Ed25519Verify_Bare(pt.Bytes("data"), pt.Int(0), pt.Bytes("key")) + + with pytest.raises(pt.TealTypeError): + pt.Ed25519Verify_Bare(pt.Bytes("data"), pt.Bytes("sig"), pt.Int(0)) + + def test_set_bit_int(): args = [pt.Int(0), pt.Int(2), pt.Int(1)] expr = pt.SetBit(args[0], args[1], args[2]) diff --git a/pyteal/ir/ops.py b/pyteal/ir/ops.py index 4a040cac0..f0e217a63 100644 --- a/pyteal/ir/ops.py +++ b/pyteal/ir/ops.py @@ -183,6 +183,7 @@ def min_version(self) -> int: replace3 = OpType("replace3", Mode.Signature | Mode.Application, 7) base64_decode = OpType("base64_decode", Mode.Application | Mode.Signature, 7) json_ref = OpType("json_ref", Mode.Signature | Mode.Application, 7) + ed25519verify_bare = OpType("ed25519verify_bare", Mode.Signature | Mode.Application, 7) sha3_256 = OpType("sha3_256", Mode.Signature | Mode.Application, 7) vrf_verify = OpType("vrf_verify", Mode.Signature | Mode.Application, 7) block = OpType("block", Mode.Signature | Mode.Application, 7)