-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ARC-63 Delegated multisig-account #303
base: main
Are you sure you want to change the base?
Conversation
This ARC proposes creating a delegated multisig-account control only by one account and a Logic signature. The motivation behind this ARC is to extend algorand account feature by enabling third-party "Plug-Ins" using a combinaison of delegated Lsig and Multi Signature accounts which act as vaults. This approach allows anyone to sign the Lsig for the vault, while maintaining security and control through a deterministic wallet and rekeying mechanisms.
Regarding line 18, there are two issues. The small one is that it's not clear if signatures are "well distributed". We want the seed to be randomly sampled from a uniform distribution and signatures are not, particularly the last 32 bytes of a signature corresponding to group element R. The bigger is that an adversary has access to both the LSigs address and the user's address. They can concatenate the two, and if they somehow can get the user to sign that (something that will be easier as we arbitrary signing becomes generally available), they now have access to the seed used to generate the new key pairs. An improvement would be to do a type of one-sided Elliptic Curve Diffie Hellman (ECDH) with the Sig address. So the user takes the LSig's address and does a scalar multiplication of it to get a new 32 byte "address" which serves as a shared secret. (Were the LSig an actual entity owning the secret key/scalar behind the LSig address, it could do the equivalent of this with the user's address.) Once the shared secret has been calculated, a more secure way of generating the seed for the new key pair would be to do Hash(shared_secret || LSig_address || user_address). This can now be used to generate a new key pair. -- However, if we take a step back, the point of this is to deterministically generate a new key pair, such that in case a user brings their seed to a new wallet, they can re-generate the key pair used for interacting with the LSig. This ties into an idea I had with HD-wallets. For ARC 52 we use BIP44 which has the following (hierarchical) derivation paths: m / purpose' / coin_type' / account' / change / address_index (This is also explained in the paper we wrote with Chris P.) In the traditional (Bitcoin) standard, change is limited to either 0 or 1. By default, since Algorand is not a uTXO but rather balance-based blockchain, we leave it to 0. I had the idea that we could possibly use those 2^32 - 1 (change = 0 left dedicated to normal Algo txn:s) to specifically be used with specific applications. If we map them 1-to-1, each application then has 2^32 child addresses available to them. 2^32 is about 4.3 billion. If we think there is still risk of overlap - and we only want 1 LSig to allow you to generate 1 address per account' (according to the BIP-44 definition) - we could use change + address_index to get ~2^64 spots, around 1.8*10^19. |
The more I think about it, the less I think a deterministic account is needed. It introduce unnecessary risks |
After thinking more about it, I removed the rekey part, it does not improve the security because anyone with the plug-in private key can still sign LSIGs inside the Multisig Account. So, if there are any concerns, the Multisig Account should be rekeyed to something else, either a normal account or another multi sig account. After this rekey, the Account will not be delegated anymore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I right in thinking this update now includes two distinct implementation designs and one will win out, or are they both being proposed as optional ways to achieve it?
I still don't think I'm onboard with either concept, but maybe I need additional examples of how this would be used beyond just opting in someones vault into an ASA.
I'd probably favour designing a simple interface that applications can implement and users can deploy from their own accounts. The complexities and increased risks involved with stateless contracts and generating delegate signatures just feels a bit archaic and messy given the features we have in the AVM today.
ARCs/arc-0063.md
Outdated
public_key, secret_key = nacl.bindings.crypto_sign_seed_keypair(base64.b64decode(plug_in_sk)[: constants.key_len_bytes]) | ||
message = constants.logic_prefix + program | ||
raw_signed = nacl.bindings.crypto_sign(message, secret_key) | ||
crypto_sign_BYTES = nacl.bindings.crypto_sign_BYTES | ||
signature = nacl.encoding.RawEncoder.encode(raw_signed[:crypto_sign_BYTES]) | ||
plug_in_public_sig = base64.b64encode(signature).decode() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is creating a signature based on the logic signature program right? Aka producing a delegate signature for the newly generated account from step 1.
Is it worth using the Algorand SDK (LogicSigAccount(program).sign(secret_key)
) in this example instead of directly using nacl? I suspect it would be clearer to our demographic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my understanding, this (LogicSigAccount(program).sign(secret_key))
method does not return the public signature def sign(self, private_key: str) -> None:
, it will instead store it inside an lsig object like this:
lsig = transaction.LogicSigAccount(program)
.sign(secret_key)
But to extract the public signature, we shoud do the following:
plug_in_public_sig = lsig.lsig.sig
It works but it seems a bit more "magical"
But you are right, I will add it for reference, so it is easier to follow what I am doing here.
ARCs/arc-0063.md
Outdated
4. **App in control of Msig Vault**: | ||
- Anyone can now call the app to opt-in any asset to the Msig vault using the plug-in signer’s public address and the published signature. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand this section. The msig account hasn't been rekeyed to the application, so how does the application control the multisig vault at this point? All it has is a list of addresses to signatures, which haven't been verified to be accurate, presumably because it's an early design? Or have I misunderstood it, and this application is just there to provide a mapping service between address and signature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the signature plug_in_public_sig
of the plug_in_addr
that is now stored on the app thanks to the set_public_sig()
method, anyone can get this value by looking at the box/ calling the get_public_sig()
method.
{
...
inner-txns:[...],
signature:{
logicsig:{
logic:"CjEQgQYSMRiB7QcSEDEgMgMSEDEBMgASEEM=",
multisig-signature:{
version:1,
threshold:1,
subsignature:[
{...},
{
public-key:"24RB9iNUHfFDelIYDnw9URA2Pf6TYz8vg/vom9sUwAI=",
signature:"iPu354yel81lxlJTlFPG34AxDVR5Bc1MLL1zRwWwK7zM2p4Ehkf5ktOH2H67avgO31a0v8ejr/DL328jNAj4BA=="
}
]
}
}
}
As
plug_in_addr
signed theteal_program
, it is enough to allow an inner transaction (binded into aLogicSigTransaction
) doing operations on the msig account.
To recontruct a multisignature to execute the application call an opt in on behalf of the user, we can just execute the code bellow.
composer.opt_in(
id=a_id,
account=app_client.app_address,
transaction_parameters=algokit_utils.TransactionParameters(
foreign_assets=[a_id], signer=app_client.signer,
sender=owner_vault_msig.address()
),
)
opt_in_txn = composer.atc.txn_list[0].txn
lsig.lsig.msig = owner_vault_msig
lsig.lsig.msig.subsigs[1].signature = base64.b64decode(plug_in_public_sig)
lstx = transaction.LogicSigTransaction(opt_in_txn, lsig)
I would rather see it as one implementation (delegated account inside msig account) being used in two different ways
Sure, all of this can be done using an app with rekeying, etc. But I try to look at it from a regulation perspective. With MICA coming, more projects will need to be regulated. We know behind the scenes it's just key/pair mapping anyway, but most of the time, regulators don't want to bother with technicalities In terms of raw cost/memory usage, you can end up spending more by using a bunch of boxes/apps for something that could have been done differently. I still think it is worth exploring just for the sake of it, and it can still be used as a reference when someone wants to know what the pros/cons and the risks involved in using lsig |
&& | ||
txn RekeyTo | ||
global ZeroAddress | ||
== |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
== | |
== | |
&& | |
txn AssetCloseTo | |
global ZeroAddress | |
== |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, to be even more strict, we could also add this:
==
global GenesisHash
byte base64(wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=)
==
&&
==
&&
txn FreezeAssetAccount
global ZeroAddress
==
This ARC proposes creating delegated multisig-account control by a single account and a logic signature.
The motivation behind this ARC is to extend Algorand account features by enabling third-party "Plug-Ins" using a combination of delegated logic signatures (Lsig) and multi-signature accounts, which act as vaults. This approach allows anyone to sign the Lsig for the vault while maintaining security and control over the account.