Skip to content

Commit

Permalink
New script and a few fixes to provide full interop with KERIpy for al…
Browse files Browse the repository at this point in the history
…l group multisig key events across client types.
  • Loading branch information
pfeairheller committed Sep 6, 2023
1 parent 48bf1f6 commit 490a39e
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 152 deletions.
139 changes: 0 additions & 139 deletions integration/app/integration_clienting.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,145 +391,6 @@ def test_delegation():
assert icp1.pre == pre


def test_multisig():
""" This test assumes a running Demo Witnesses and KERIA agent with the following comands:
`kli witness demo`
`keria start --config-file demo-witness-oobis --config-dir <path to KERIpy>/scripts`
"""
url = "http://localhost:3901"
bran = b'0123456789abcdefghijk'
tier = Tiers.low

client = SignifyClient(passcode=bran, tier=tier)
print(client.controller)
assert client.controller == "ELI7pg979AdhmvrjDeam2eAO2SR5niCgnjAJXJHtJose"

evt, siger = client.ctrl.event()
res = requests.post(url="http://localhost:3903/boot",
json=dict(
icp=evt.ked,
sig=siger.qb64,
stem=client.ctrl.stem,
pidx=1,
tier=client.ctrl.tier))

client.connect(url=url)
assert client.agent is not None
assert client.agent.delpre == "ELI7pg979AdhmvrjDeam2eAO2SR5niCgnjAJXJHtJose"
assert client.agent.pre == "EEXekkGu9IAzav6pZVJhkLnjtjM5v3AcyA-pdKUcaGei"
# assert client.ctrl.ridx == 0

if res.status_code != requests.codes.accepted:
raise kering.AuthNError(f"unable to initialize cloud agent connection, {res.status_code}, {res.text}")

identifiers = client.identifiers()
operations = client.operations()
oobis = client.oobis()

op = identifiers.create("multisig3", bran="0123456789lmnopqrstuv")
icp = op["response"]
serder = coring.Serder(ked=icp)
assert serder.pre == "EOGvmhJDBbJP4zeXaRun5vSz0O3_1zB10DwNMyjXlJEv"
print(f"created AID {serder.pre}")

identifiers.addEndRole("multisig3", eid=client.agent.pre)

print(f"OOBI for {serder.pre}:")
oobi = oobis.get("multisig3")
print(oobi)

op = oobis.resolve(oobi="http://127.0.0.1:5642/oobi/EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4/witness/BBilc4"
"-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha",
alias="multisig1")

print("resolving oobi for multisig1")
while not op["done"]:
op = operations.get(op["name"])
sleep(1)

multisig1 = op["response"]
print("resolving oobi for multisig2")
op = oobis.resolve(oobi="http://127.0.0.1:5642/oobi/EJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1/witness/BBilc4"
"-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha",
alias="multisig2")

while not op["done"]:
op = operations.get(op["name"])
sleep(1)
multisig2 = op["response"]

m3 = identifiers.get("multisig3")
agent0 = m3["state"]
print(f"agent is {agent0}")

states = rstates = [multisig2, multisig1, agent0]

op = identifiers.create("multisig", algo=Algos.group, mhab=m3,
isith=["1/3", "1/3", "1/3"], nsith=["1/3", "1/3", "1/3"],
toad=3,
wits=[
"BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha",
"BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM",
"BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX"
],
states=states,
rstates=rstates)
print("waiting on multisig creation...")
while not op["done"]:
op = operations.get(op["name"])
sleep(1)
gAid = op["response"]
print(f"group multisig created {gAid}")

# Join an interaction event with the group
data = {"i": "EE77q3_zWb5ojgJr-R1vzsL5yiL4Nzm-bfSOQzQl02dy"}
op = identifiers.interact("multisig", data=data)
while not op["done"]:
op = operations.get(op["name"])
sleep(1)

ixn = coring.Serder(ked=op["response"])
events = client.keyEvents()
log = events.get(pre=ixn.pre)
assert len(log) == 2

for event in log:
print(coring.Serder(ked=event).pretty())

op2 = identifiers.rotate("multisig3")
rot = op2["response"]
serder = coring.Serder(ked=rot)
print(f"rotated multisig3 to {serder.sn}")

aid1 = identifiers.get("multisig3")
agent0 = aid1["state"]
keyState = client.keyStates()
op = keyState.query(pre="EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4", sn=1)
while not op["done"]:
op = operations.get(op["name"])
sleep(1)

multisig1 = op["response"]
print(f"using key {multisig1['k'][0]}")
print(f"using dig {multisig1['n'][0]}")

op = keyState.query(pre="EJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1", sn=1)
while not op["done"]:
op = operations.get(op["name"])
sleep(1)

multisig2 = op["response"]
print(f"using key {multisig2['k'][0]}")
print(f"using dig {multisig2['n'][0]}")

states = rstates = [multisig1, multisig2, agent0]

op = identifiers.rotate("multisig", states=states, rstates=rstates)
print(op)


def test_randy():
""" This test assumes a running KERIA agent with the following comand:
Expand Down
4 changes: 0 additions & 4 deletions scripts/multisig-endrole.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
Testing clienting with integration tests that require a running KERIA Cloud Agent
"""

import json
from time import sleep

from keri.app.keeping import Algos
from keri.core.coring import Tiers
from signify.app.clienting import SignifyClient

Expand Down
186 changes: 186 additions & 0 deletions scripts/multisig-kli-rotation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
from time import sleep

import requests
from keri import kering
from keri.app.keeping import Algos
from keri.core import coring, eventing
from keri.core.coring import Tiers
from signify.app.clienting import SignifyClient


def create_multisig():
url = "http://localhost:3901"
bran = b'0123456789abcdefghijk'
tier = Tiers.low

client = SignifyClient(passcode=bran, tier=tier)
print(client.controller)
assert client.controller == "ELI7pg979AdhmvrjDeam2eAO2SR5niCgnjAJXJHtJose"

evt, siger = client.ctrl.event()
res = requests.post(url="http://localhost:3903/boot",
json=dict(
icp=evt.ked,
sig=siger.qb64,
stem=client.ctrl.stem,
pidx=1,
tier=client.ctrl.tier))

client.connect(url=url)
assert client.agent is not None
assert client.agent.delpre == "ELI7pg979AdhmvrjDeam2eAO2SR5niCgnjAJXJHtJose"
assert client.agent.pre == "EEXekkGu9IAzav6pZVJhkLnjtjM5v3AcyA-pdKUcaGei"
# assert client.ctrl.ridx == 0

if res.status_code != requests.codes.accepted:
raise kering.AuthNError(f"unable to initialize cloud agent connection, {res.status_code}, {res.text}")

identifiers = client.identifiers()
operations = client.operations()
oobis = client.oobis()
exchanges = client.exchanges()

(_, _, op) = identifiers.create("multisig3", bran="0123456789lmnopqrstuv")
icp = op["response"]
serder = coring.Serder(ked=icp)
assert serder.pre == "EOGvmhJDBbJP4zeXaRun5vSz0O3_1zB10DwNMyjXlJEv"
print(f"created AID {serder.pre}")

identifiers.addEndRole("multisig3", eid=client.agent.pre)

print(f"OOBI for {serder.pre}:")
oobi = oobis.get("multisig3")
print(oobi)

op = oobis.resolve(oobi="http://127.0.0.1:5642/oobi/EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4/witness",
alias="multisig1")

print("resolving oobi for multisig1")
while not op["done"]:
op = operations.get(op["name"])
sleep(1)
print("... done")

multisig1 = op["response"]
print("resolving oobi for multisig2")
op = oobis.resolve(oobi="http://127.0.0.1:5642/oobi/EJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1/witness",
alias="multisig2")
print("... done")

while not op["done"]:
op = operations.get(op["name"])
sleep(1)
multisig2 = op["response"]

m3 = identifiers.get("multisig3")
agent0 = m3["state"]
print(f"agent is {agent0}")

states = rstates = [multisig2, multisig1, agent0]

icp, isigs, op = identifiers.create("multisig", algo=Algos.group, mhab=m3,
isith=["1/3", "1/3", "1/3"], nsith=["1/3", "1/3", "1/3"],
toad=3,
wits=[
"BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha",
"BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM",
"BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX"
],
states=states,
rstates=rstates)

smids = [state['i'] for state in states]
recp = [state['i'] for state in [multisig2, multisig1]]

embeds = dict(
icp=eventing.messagize(serder=icp, sigers=[coring.Siger(qb64=sig) for sig in isigs])
)

exchanges.send("multisig3", "multisig", sender=m3, route="/multisig/icp",
payload=dict(gid=icp.pre, smids=smids, rmids=smids),
embeds=embeds, recipients=recp)

print("waiting on multisig creation...")
while not op["done"]:
op = operations.get(op["name"])
sleep(1)
gAid = op["response"]
print(f"group multisig created {gAid}")

# Join an interaction event with the group
data = {"i": "EE77q3_zWb5ojgJr-R1vzsL5yiL4Nzm-bfSOQzQl02dy"}
ixn, xsigs, op = identifiers.interact("multisig", data=data)

embeds = dict(
ixn=eventing.messagize(serder=ixn, sigers=[coring.Siger(qb64=sig) for sig in xsigs])
)

exchanges.send("multisig3", "multisig", sender=m3, route="/multisig/ixn",
payload=dict(gid=icp.pre, smids=smids),
embeds=embeds, recipients=recp)

print("waiting for ixn to finish...")
while not op["done"]:
op = operations.get(op["name"])
sleep(1)

ixn = coring.Serder(ked=op["response"])
events = client.keyEvents()
log = events.get(pre=ixn.pre)
assert len(log) == 2

for event in log:
print(coring.Serder(ked=event).pretty())

(_, _, op2) = identifiers.rotate("multisig3")
rot = op2["response"]
serder = coring.Serder(ked=rot)
print(f"rotated multisig3 to {serder.sn}")

input("hit any key when other two participants have rotated their AIDs")

m3 = identifiers.get("multisig3")
agent0 = m3["state"]

keyState = client.keyStates()
op = keyState.query(pre="EJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1", sn=1)
while not op["done"]:
op = operations.get(op["name"])
sleep(1)

multisig2 = op["response"]
print(f"using key {multisig2['k'][0]}")
print(f"using dig {multisig2['n'][0]}")

op = keyState.query(pre="EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4", sn=1)
while not op["done"]:
op = operations.get(op["name"])
sleep(1)

multisig1 = op["response"]
print(f"using key {multisig1['k'][0]}")
print(f"using dig {multisig1['n'][0]}")

states = rstates = [multisig1, multisig2, agent0]

rot, rsigs, op = identifiers.rotate("multisig", states=states, rstates=rstates)
embeds = dict(
rot=eventing.messagize(serder=rot, sigers=[coring.Siger(qb64=sig) for sig in rsigs])
)

smids = [state['i'] for state in states]
recp = [state['i'] for state in [multisig1, multisig2]]

rexn, _, _ = exchanges.send("multisig3", "multisig", sender=m3, route="/multisig/rot",
payload=dict(gid=icp.pre, smids=smids, rmids=smids),
embeds=embeds, recipients=recp)

print(rexn.pretty(size=5000))
print("Waiting for multisig rotation...")
while not op["done"]:
op = operations.get(op["name"])
sleep(1)


if __name__ == "__main__":
create_multisig()
4 changes: 2 additions & 2 deletions src/signify/app/aiding.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def interact(self, name, data=None):
json[keeper.algo] = keeper.params()

res = self.client.put(f"/identifiers/{name}?type=ixn", json=json)
return res.json()
return serder, sigs, res.json()

def rotate(self, name, *, transferable=True, nsith=None, toad=None, cuts=None, adds=None,
data=None, ncode=MtrDex.Ed25519_Seed, ncount=1, ncodes=None, states=None, rstates=None):
Expand Down Expand Up @@ -181,7 +181,7 @@ def rotate(self, name, *, transferable=True, nsith=None, toad=None, cuts=None, a
json['rmids'] = [state['i'] for state in rstates]

res = self.client.put(f"/identifiers/{name}", json=json)
return res.json()
return serder, sigs, res.json()

def addEndRole(self, name, *, role=Roles.agent, eid=None, stamp=None):
hab = self.get(name)
Expand Down
6 changes: 3 additions & 3 deletions src/signify/core/keeping.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ def new(self, algo, pidx, **kwargs):
def get(self, aid):
pre = coring.Prefixer(qb64=aid["prefix"])
if keeping.Algos.salty in aid:
if "pidx" not in aid:
raise kering.ConfigurationError(f"missing pidx in {aid}")
kwargs = aid[keeping.Algos.salty]
return SaltyKeeper(salter=self.salter, pidx=aid["pidx"], **kwargs)
if "pidx" not in kwargs:
raise kering.ConfigurationError(f"missing pidx in {kwargs}")
return SaltyKeeper(salter=self.salter, **kwargs)

elif keeping.Algos.randy in aid:
kwargs = aid[keeping.Algos.randy]
Expand Down
2 changes: 1 addition & 1 deletion src/signify/peer/exchanging.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def send(self, name, topic, sender, route, payload, embeds, recipients):
rec=recipients
)

self.client.post(f"/identifiers/{name}/exchanges", json=body)
return exn, sigs, self.client.post(f"/identifiers/{name}/exchanges", json=body)

def createExchangeMessage(self, sender, route, payload, embeds):
""" Create exn message from parameters and return Serder with signatures and additional attachments.
Expand Down
2 changes: 1 addition & 1 deletion tests/app/test_aiding.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def test_aiding_rotate():
expect(mock_client, times=1).put('/identifiers/aid1', json=expected_data).thenReturn(mock_response)
expect(mock_response, times=1).json().thenReturn({'success': 'yay'})

out = ids.rotate(name='aid1', states=[{'i': 'state 1'}, {'i': 'state 2'}],
_, _, out = ids.rotate(name='aid1', states=[{'i': 'state 1'}, {'i': 'state 2'}],
rstates=[{'i': 'rstate 1'}, {'i': 'rstate 2'}])
assert out['success'] == 'yay'

Expand Down
Loading

0 comments on commit 490a39e

Please sign in to comment.