Index: nano.tcl ================================================================== --- nano.tcl +++ nano.tcl @@ -28,10 +28,11 @@ namespace eval ::nano::network::server {} namespace eval ::nano::protocol::create {} namespace eval ::nano::protocol::parse {} namespace eval ::nano::protocol::extensions {} namespace eval ::nano::network::_dns {} +namespace eval ::nano::wallet {} namespace eval ::nano::_cli {} # Constants set ::nano::block::genesis(main) {{ "type": "open", @@ -4078,10 +4079,43 @@ } proc {::nano::_cli::multiword help} {namespace base args} { tailcall help $namespace $base {*}$args } + +# Node Wallet Functions +proc ::nano::wallet::decode_backup {password walletJSON} { + array set walletArray [::json::json2dict $walletJSON] + + set wallet(version) [expr 0x$walletArray(0000000000000000000000000000000000000000000000000000000000000000)] + set wallet(salt) [binary decode hex $walletArray(0000000000000000000000000000000000000000000000000000000000000001)] + set wallet(key) [binary decode hex $walletArray(0000000000000000000000000000000000000000000000000000000000000002)] + set wallet(check) [binary decode hex $walletArray(0000000000000000000000000000000000000000000000000000000000000003)] + set wallet(rep) [::nano::address::fromPublicKey $walletArray(0000000000000000000000000000000000000000000000000000000000000004)] + set wallet(seed) [binary decode hex $walletArray(0000000000000000000000000000000000000000000000000000000000000005)] + set wallet(index) [expr 0x$walletArray(0000000000000000000000000000000000000000000000000000000000000006)] + + if {$wallet(version) != 4} { + return -code error "Unsupported wallet backup version ($version)" + } + + set password "" + set walletKeyIV [string range $wallet(salt) 0 15] + set seedIV [string range $wallet(salt) 16 end] + + # Decrypt seed + set aesKey [::nano::internal::deriveKeyFromPassword $password $wallet(salt)] + set walletKey [::nano::internal::AES256-CTR $aesKey $walletKeyIV $wallet(key)] + set seed [::nano::internal::AES256-CTR $walletKey $seedIV $wallet(seed)] + + # Format results + set wallet(seed) [string toupper [binary encode hex $seed]] + + # XXX:TODO: Include ad-hoc keys + + return [array get wallet] +} # Node CLI proc ::nano::node::cli {args} { tailcall ::nano::_cli node -prompt { return "\[[dict get $::nano::node::configuration network]\] nano-node [package present nano]> " Index: test/test.tcl ================================================================== --- test/test.tcl +++ test/test.tcl @@ -416,10 +416,33 @@ return false } return true } + +proc test_wallet {} { + set expectedSeed "7ED0C65229A00520A9CDD2C18C1172EFDF34467A8785E5D8D30916E4F6122273" + set walletJSON {{ + "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000004", + "0000000000000000000000000000000000000000000000000000000000000001": "F551DD44FC8A78D40BAF56ACD96390251246ADE5C805778EB54F3F28B84A8C84", + "0000000000000000000000000000000000000000000000000000000000000002": "520E57026946425A4E1FF5596BF8B1D325AE43C63C11CC357CB598F8C934765A", + "0000000000000000000000000000000000000000000000000000000000000003": "D28BBF12ADEB7C066205BEDA7F37904BD86B311DDE0FD06481144EBC89B00790", + "0000000000000000000000000000000000000000000000000000000000000004": "2399A083C600AA0572F5E36247D978FCFC840405F8D4B6D33161C0066A55F431", + "0000000000000000000000000000000000000000000000000000000000000005": "685FCF7537EE1AA8055638C5C278FBBEE77C0242D8A6F054534E476EE33F33FF", + "0000000000000000000000000000000000000000000000000000000000000006": "0000000000000000000000000000000000000000000000000000000000000000" + }} + array set wallet [::nano::wallet::decode_backup "" $walletJSON] + + if {$wallet(seed) ne $expectedSeed} { + puts "\[1.FAIL\] Got: $wallet(seed)" + puts "\[1.FAIL\] Exp: $expectedSeed" + + return false + } + + return true +} set tests { selftest signatures hashing @@ -426,10 +449,11 @@ keygeneration addressformat blocks work balances + wallet } foreach test $tests { puts -nonewline "\[ \] $test" flush stdout