1import smartpy as sp
2
3
4@sp.module
5def main():
6 class TestCheckSignature(sp.Contract):
7 def __init__(self, boss_pk):
8 self.data.currentValue = "Hello World"
9 self.data.counter = 0
10 self.data.bossPublicKey = boss_pk
11
12 @sp.entrypoint
13 def setCurrentValue(self, params):
14 # We will also need Michelson SELF and CHAIN_ID to avoid all replay attacks:
15 thingToSign = sp.pack(
16 sp.record(
17 o=self.data.currentValue, n=params.newValue, c=self.data.counter
18 )
19 )
20 assert sp.check_signature(
21 self.data.bossPublicKey, params.userSignature, thingToSign
22 )
23 self.data.currentValue = params.newValue
24 self.data.counter = self.data.counter + 1
25
26
27@sp.add_test()
28def test():
29 scenario = sp.test_scenario("CheckSignature", main)
30 scenario.h1("Check Signature")
31 rightful_owner = sp.test_account("Alice")
32 attacker = sp.test_account("Robert")
33 c1 = main.TestCheckSignature(rightful_owner.public_key)
34
35 scenario += c1
36 # Let's build a successful call:
37 #
38 scenario.h2("Successful Call")
39 first_message_packed = sp.pack(sp.record(o="Hello World", n="should work", c=0))
40 sig_from_alice = sp.make_signature(
41 secret_key=rightful_owner.secret_key,
42 message=first_message_packed,
43 message_format="Raw",
44 )
45 c1.setCurrentValue(
46 newValue="should work", userSignature=sig_from_alice, _valid=True
47 )
48 #
49 scenario.h2("Replay Attack")
50 scenario.p(
51 "Trying to reuse the same signature is blocked by the value of the counter."
52 )
53 c1.setCurrentValue(
54 newValue="should work", userSignature=sig_from_alice, _valid=False
55 )
56 #
57 #
58 scenario.h2("Signature From Wrong Secret Key")
59 scenario.p("Signing the right thing from a different secret-key.")
60 #
61 #
62 # Gives:
63 second_message_packed = sp.pack(
64 sp.record(o="should work", n="Hello again World", c=1)
65 )
66 sig_from_bob = sp.make_signature(
67 secret_key=attacker.secret_key,
68 message=second_message_packed,
69 message_format="Raw",
70 )
71 c1.setCurrentValue(
72 newValue="Hello again World", userSignature=sig_from_bob, _valid=False
73 )
74 #
75 scenario.h2("Second Successful Call")
76 scenario.p(
77 "Showing that the previous call failed <b>because</b> of the secret-key (signing same bytes)."
78 )
79 sig_from_alice = sp.make_signature(
80 secret_key=rightful_owner.secret_key,
81 message=second_message_packed,
82 message_format="Raw",
83 )
84 c1.setCurrentValue(
85 newValue="Hello again World", userSignature=sig_from_alice, _valid=True
86 )