1
0
mirror of https://github.com/danog/toncontest.git synced 2024-11-30 04:29:14 +01:00
This commit is contained in:
Daniil Gentili 2019-10-11 16:54:08 +02:00
parent 5fe76ed22b
commit c7a6366724
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
9 changed files with 110 additions and 50 deletions

6
wallet/README.md Normal file
View File

@ -0,0 +1,6 @@
# Multisignature wallet
Upgradable multisignature wallet.
Included signature verification scripts to avoid problems with eventual preloaded orders with invalid signatures.
Code can be upgraded via a special multisignature message.

View File

@ -39,9 +39,9 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr
body-cell <s 2dup s-fits? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
b>
// create wrapper message
// modeMessage$_ mode:uint8 body:^(Message X) = ModeMessage X;
// modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
// wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
<b now timeout + 32 u, seqno 32 u, send-mode 8 u, swap ref, b>
<b now timeout + 32 u, seqno 32 u, 0 1 u, send-mode 8 u, swap ref, b>
dup ."signing message: " <s csr. cr
dup hashu
@ -54,7 +54,14 @@ wallet_pk ed25519_sign_uint
// key ID => signature
// multiSigWrapper$0 signatures:(HashmapE 4 Signature) message:(WrappedMessage X) = MultiSigWrapper X;
<b swap <s key-id dictnew 4 udict! not abort"Failure inserting signature!" dict, swap <s s, b>
<b
0 1 u, // $0
swap <s key-id dictnew 4 udict! // Create and populate dictionary
not abort"Failure inserting signature!"
dict, // signatures
swap <s s, // message
b>
//
// addr_none$00 = MsgAddressExt;

View File

@ -21,16 +21,27 @@
// D n -- uint
{
0 -rot
{ drop swap 1+ swap -1 } dictmap
{ drop swap 1+ swap -1 } dictmap drop
} : dictlen
// u D n -- s ? or ?
{
{ swap 2 pick = { nip 0 } { drop -1 } cond } dictforeach
dup ' nip if
not
} : dict[]
{ hole dup 1 ' @ does create 1 ' ! does create } : variable-set
{ hole hole 2dup 2 { @ swap @ swap } does create 2 { rot swap ! ! } does create } : 2variable-set
2variable-set wallet-addr wallet-addr!
variable-set message-hash message-hash!
variable-set message-contents message-contents!
variable-set sig-count sig-count!
// udata BSig ukey ?
{
256 u>B rot 256 u>B -rot ed25519_chksign
} : ed25519_chksignuu
// Inspects contents of cell provided on top of the stack
// c --
@ -99,6 +110,7 @@ variable-set message-contents message-contents!
dict@+ swap
dup null? abort"Empty signature list!"
dup 4 dictlen sig-count!
."Signed by the following keys: "
4 { drop . ."- " -1 } dictforeach cr drop
@ -106,7 +118,7 @@ variable-set message-contents message-contents!
."Hash: " dup s>c hashu dup x. cr
message-hash!
// modeMessage$_ mode:uint8 body:^(Message X) = ModeMessage X;
// modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
// wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
32 u@+ swap
@ -116,6 +128,9 @@ variable-set message-contents message-contents!
32 u@+ swap
."Seqno: " . cr
1 u@+ swap
{ ."Is code message!" cr ref@ <s quit } if
8 u@+ swap
."Mode: " . cr

View File

@ -8,7 +8,9 @@ pubKey$_ k:bits256 = PubKey;
signature$_ R:bits256 s:bits256 = Signature;
// Message + send ModeMessage
modeMessage$_ mode:uint8 body:^(Message X) = ModeMessage X;
modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
// Special code upgrade message
codeMessage$1 code:^Cell = ModeMessage X;
// Actual multisigned message
wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;

View File

@ -32,7 +32,7 @@ dup hash wallet_pk ed25519_sign_uint
256 B>u@+ swap 256 B>u@ swap
<b swap 256 u, swap 256 u, b> <s
roll
.s rot
// Now we have (message) value dict
// udict! => value key dict bits

41
wallet/verify.fif Normal file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env -S fift -s
"TonUtil.fif" include
"lib.fif" include
{
."usage: " @' $0 type ." <input> <key1> <key1-id> [<key2> <key2-id> ...]" cr
."Verify multisig <input>.boc file with public key <keyN-id> loaded from file <keyN>.pubkey" cr 1 halt
} : usage
$# 3 < ' usage if
$# 3 - 2 mod ' usage if
$1 +".boc" load-boc constant order
order inspect cr
// multiSigWrapper$0 signatures:(HashmapE 4 Signature) message:(WrappedMessage X) = MultiSigWrapper X;
message-contents
1 u@+ nip // $0 was already verified
// multiSigWrapper$0 signatures:(HashmapE 4 Signature) message:(WrappedMessage X) = MultiSigWrapper X;
dict@ const signatures
variable-set key key!
variable-set key-id key-id!
2 { dup 1+ swap // Counter
$() +".pubkey" load-pubkey key!
dup 1+ swap // Increment counter
$() parse-int key-id!
."Checking signature of key ID " key-id . ."... "
key-id signatures 4 dict[] // Find signature
not abort"Could not find signature with specified key ID!"
64 B@
// udata BSig ukey ?
message-hash swap key
ed25519_chksignuu
not abort"Invalid signature!"
."OK!" cr
} $# 1- 2 /c times

View File

@ -21,7 +21,7 @@ int udict_has?(cell dict, int key_len, int index) asm(index dict key_len) "DICTU
do {
(hash, var cs, int ok) = messages.udict_get_next?(256, hash);
if (ok) {
;; modeMessage$_ mode:uint8 body:^(Message X) = ModeMessage X;
;; modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
;; wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
;; multiSigWrapperStorage$_ signatures:(HashmapE 4 Signature) message:(WrappedMessage X) = MultiSigWrapperStorage X;
;;
@ -110,14 +110,19 @@ int udict_has?(cell dict, int key_len, int index) asm(index dict key_len) "DICTU
}
} until (~ ok);
var (mode, message) = (message_data~load_uint(8), message_data~load_ref());
message_data.end_parse();
if (storedSignatureCount >= min_sigs) {
send_raw_message(message, mode);
if (message_data~load_uint(1)) {
;; Code upgrade
set_code(message_data~load_ref());
} else {
;; Simple message
var (mode, message) = (message_data~load_uint(8), message_data~load_ref());
send_raw_message(message, mode);
}
message_data.end_parse();
messages~udict_delete?(256, hash);
} else {
;; modeMessage$_ mode:uint8 body:^(Message X) = ModeMessage X;
;; modeMessage$0 mode:uint8 body:^(Message X) = ModeMessage X;
;; wrappedMessage$_ expires_at:uint32 seqno:uint32 body:(ModeMessage X) = WrappedMessage X;
;; multiSigWrapperStorage$_ count:(## 4) signatures:(HashmapE 4 Signature) message:(WrappedMessage X) = MultiSigWrapperStorage X;
;;

View File

@ -152,24 +152,32 @@ PROGRAM{
}>
DROP
s9 POP
s0 s6 XCHG
8 LDU
LDREF
ENDS
s4 s3 PUSH2
2OVER
GEQ
IF:<{
s3 POP
s4 POP
s5 POP
s6 POP
s0 s3 XCHG
SENDRAWMSG
1 LDU
SWAP
IF:<{
LDREF
SWAP
SETCODE
}>ELSE<{
8 LDU
LDREF
s0 s2 XCHG
SENDRAWMSG
}>
ENDS
ROT
8 PUSHPOW2
DICTUDEL
DROP
}>ELSE<{
2DROP
s6 POP
4 PUSHINT
NEWC
s1 s0 s4 XCHG3
@ -181,12 +189,14 @@ PROGRAM{
s0 s1 s3 XCHG3
8 PUSHPOW2
DICTUSETB
s1 s2 XCHG
}>
~collect_garbage CALLDICT
s0 s3 XCHG
INC
NEWC
32 STU
s1 s2 XCHG
4 STU
STDICT
STDICT

View File

@ -1,7 +1,7 @@
"TonUtil.fif" include
"lib.fif" include
{ ."usage: " @' $0 type ." <workchain-id> <wallet-name> <n> <k> <privkey1> [<pubkey2> ...] [<boc1> <boc2>]" cr cr
{ ."usage: " @' $0 type ." <workchain-id> <wallet-name> <n> <k> <privkey1> [<pubkey2> ...]" cr cr
."Creates a new multisignature wallet in specified workchain composed of <n> (1-10) keys." cr
."The first of the keys must be a private key (pre-existing or not), used to generate the wallet; the rest MUST be public keys." cr
."Create or generate public key files from private keys using gen-pub.fif privkey" cr cr
@ -15,7 +15,6 @@ $1 parse-workchain-id =: wc // set workchain id from command line argument
$2 constant file-base
$3 (number) 1 <> abort"<n> must be a number!" constant n
$4 (number) 1 <> abort"<k> must be a number!" constant k
$# 4 n + - constant m
n 1 < n 10 > or abort"<n> must be between 1 and 10"
k 1 < k 10 > or abort"<k> must be between 1 and 10"
@ -28,14 +27,11 @@ $5 +".pk" load-generate-keypair const privkey 256 B>u@
6 { dup $() +".pubkey" load-pubkey swap 1+ } n 1- times drop
n tuple constant keys
5 n + { dup $() +".boc" load-boc swap 1+ } m times drop
m tuple constant messages
cr
."Creating new advanced wallet in workchain " wc .
."with n=" n .
."k=" k .
."m=" m . ."..." cr cr
."k=" k . ."..." cr cr
// idict! (v x s n s0 1 or s 0), adds a new value v (represented
// by a Slice) with key given by signed big-endian n-bit integer x into
@ -60,28 +56,6 @@ rot // Put length on top for times
swap
} swap times drop const keys-dict
// Extract internal messages
messages explode
dictnew swap
{
swap // Get n-th value
inspect
message-contents // Get v
1 u@+ nip // Remove $0
dict@+ swap // ...get signatures
dup dictlen // ...and signature count
<b swap 4 u, swap dict, swap s, // Finally rebuild cell
message-hash // Get x
rot // Get dictionary s
256 // Get n
b>udict!
not abort"Failure storing dictionary value!"
swap
} swap times const messages-dict
// code
"wallet-code.fif" include
// data
@ -90,7 +64,7 @@ dictnew swap
<b 0 32 u,
k 4 u,
keys-dict dict,
messages-dict dict,
dictnew dict,
b>
// no libraries
null