From c7a63667242b9ceda2d792b4c59e574141529049 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 11 Oct 2019 16:54:08 +0200 Subject: [PATCH] update --- wallet/README.md | 6 ++++++ wallet/create.fif | 13 ++++++++++--- wallet/lib.fif | 19 +++++++++++++++++-- wallet/scheme.tlb | 4 +++- wallet/sign.fif | 2 +- wallet/verify.fif | 41 ++++++++++++++++++++++++++++++++++++++++ wallet/wallet-code.fc | 17 +++++++++++------ wallet/wallet-code.fif | 26 +++++++++++++++++-------- wallet/wallet-create.fif | 32 +++---------------------------- 9 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 wallet/README.md create mode 100644 wallet/verify.fif diff --git a/wallet/README.md b/wallet/README.md new file mode 100644 index 0000000..a2ad161 --- /dev/null +++ b/wallet/README.md @@ -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. \ No newline at end of file diff --git a/wallet/create.fif b/wallet/create.fif index eff04d0..1f82a1b 100755 --- a/wallet/create.fif +++ b/wallet/create.fif @@ -39,9 +39,9 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr body-cell // 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; - + dup ."signing message: " signature // multiSigWrapper$0 signatures:(HashmapE 4 Signature) message:(WrappedMessage X) = MultiSigWrapper X; - + // // addr_none$00 = MsgAddressExt; diff --git a/wallet/lib.fif b/wallet/lib.fif index 888252b..541c0bf 100644 --- a/wallet/lib.fif +++ b/wallet/lib.fif @@ -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@ u@+ swap 256 B>u@ swap value key dict bits diff --git a/wallet/verify.fif b/wallet/verify.fif new file mode 100644 index 0000000..2df04ee --- /dev/null +++ b/wallet/verify.fif @@ -0,0 +1,41 @@ +#!/usr/bin/env -S fift -s +"TonUtil.fif" include +"lib.fif" include + +{ + ."usage: " @' $0 type ." [ ...]" cr + ."Verify multisig .boc file with public key loaded from file .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 \ No newline at end of file diff --git a/wallet/wallet-code.fc b/wallet/wallet-code.fc index 67866f0..2bb09fd 100644 --- a/wallet/wallet-code.fc +++ b/wallet/wallet-code.fc @@ -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; ;; diff --git a/wallet/wallet-code.fif b/wallet/wallet-code.fif index 210a6d7..116e6e8 100644 --- a/wallet/wallet-code.fif +++ b/wallet/wallet-code.fif @@ -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 diff --git a/wallet/wallet-create.fif b/wallet/wallet-create.fif index 6cda0a8..836d8b5 100644 --- a/wallet/wallet-create.fif +++ b/wallet/wallet-create.fif @@ -1,7 +1,7 @@ "TonUtil.fif" include "lib.fif" include -{ ."usage: " @' $0 type ." [ ...] [ ]" cr cr +{ ."usage: " @' $0 type ." [ ...]" cr cr ."Creates a new multisignature wallet in specified workchain composed of (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" must be a number!" constant n $4 (number) 1 <> abort" must be a number!" constant k -$# 4 n + - constant m n 1 < n 10 > or abort" must be between 1 and 10" k 1 < k 10 > or abort" 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 - 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 // no libraries null