diff options
author | John Wiegley <johnw@newartisans.com> | 2023-11-30 12:38:44 -0800 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2024-08-05 08:35:56 -0700 |
commit | 75e5eacebaf8b9ad3a18b6f1a91a8cb227fa5c9c (patch) | |
tree | 896d7f2d1496bd19b2c5ba7a8b97285908bfde0c | |
parent | f230125ecc0761e6bd082ac0d916db4f17f0278d (diff) | |
download | fork-ledger-75e5eacebaf8b9ad3a18b6f1a91a8cb227fa5c9c.tar.gz fork-ledger-75e5eacebaf8b9ad3a18b6f1a91a8cb227fa5c9c.tar.bz2 fork-ledger-75e5eacebaf8b9ad3a18b6f1a91a8cb227fa5c9c.zip |
Add support for --hashes=sha512_256 as another algorithm
-rw-r--r-- | doc/ledger.1 | 11 | ||||
-rw-r--r-- | doc/ledger3.texi | 9 | ||||
-rw-r--r-- | src/generate.cc | 2 | ||||
-rw-r--r-- | src/global.cc | 2 | ||||
-rw-r--r-- | src/journal.cc | 5 | ||||
-rw-r--r-- | src/journal.h | 6 | ||||
-rw-r--r-- | src/precmd.cc | 2 | ||||
-rw-r--r-- | src/session.cc | 6 | ||||
-rw-r--r-- | src/session.h | 7 | ||||
-rw-r--r-- | src/textual.cc | 18 | ||||
-rw-r--r-- | src/utils.h | 6 | ||||
-rw-r--r-- | src/xact.cc | 5 | ||||
-rw-r--r-- | src/xact.h | 2 | ||||
-rw-r--r-- | test/baseline/opt-hashes-sha512_256.test | 28 |
14 files changed, 81 insertions, 28 deletions
diff --git a/doc/ledger.1 b/doc/ledger.1 index febfaf1e..0e5ac7e7 100644 --- a/doc/ledger.1 +++ b/doc/ledger.1 @@ -1,4 +1,4 @@ -.Dd November 23, 2023 +.Dd November 30, 2023 .Dt LEDGER 1 .Os .Sh NAME @@ -639,7 +639,14 @@ Record the hash of each transaction in a .Ar Hash metadata value, according to the hashing algorithm given by the .Ar ALGO -argument. Note that if a +argument. Support algorithms are +.Ar sha512 +or +.Ar sh512_256 +where both use SHA512, but the latter only stores the first half of +the hash value. +.Pp +If a .Ar Hash metadata value is explicitly provided and does not match what would have been generated, an error is reported. Hashes depend on previous diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 494847ca..13219758 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -6765,6 +6765,15 @@ they do not match, an error is reported. You may also write just a prefix of the @var{Hash}, which is less verbose but still gives quite good assurance. +The support algorithms are: + +@table @code +@item sha512 +Use the SHA512 hashing algorithm. +@item sha512_256 +Same as SHA512, but record only the first 256 bits. +@end table + Somewhat like balance assertions, which give assurance that previous posting amounts are correct, these @var{Hash} tags give assurance that all previous journal entries (in parse order) are unchanged (or at diff --git a/src/generate.cc b/src/generate.cc index 98986c67..ee820c98 100644 --- a/src/generate.cc +++ b/src/generate.cc @@ -365,7 +365,7 @@ void generate_posts_iterator::increment() parsing_context.get_current().journal = session.journal.get(); parsing_context.get_current().scope = &session; - if (session.journal->read(parsing_context, false) != 0) { + if (session.journal->read(parsing_context, NO_HASHES) != 0) { VERIFY(session.journal->xacts.back()->valid()); posts.reset(*session.journal->xacts.back()); post = *posts++; diff --git a/src/global.cc b/src/global.cc index ad1001ef..050a1d51 100644 --- a/src/global.cc +++ b/src/global.cc @@ -116,7 +116,7 @@ void global_scope_t::parse_init(path init_file) parsing_context.get_current().journal = session().journal.get(); parsing_context.get_current().scope = &report(); - if (session().journal->read(parsing_context, false) > 0 || + if (session().journal->read(parsing_context, NO_HASHES) > 0 || session().journal->auto_xacts.size() > 0 || session().journal->period_xacts.size() > 0) { throw_(parse_error, _f("Transactions found in initialization file '%1%'") diff --git a/src/journal.cc b/src/journal.cc index b5ae3f1b..62e33440 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -466,7 +466,8 @@ bool journal_t::remove_xact(xact_t * xact) return true; } -std::size_t journal_t::read(parse_context_stack_t& context, bool store_hashes) +std::size_t journal_t::read(parse_context_stack_t& context, + hash_type_t hash_type) { std::size_t count = 0; try { @@ -485,7 +486,7 @@ std::size_t journal_t::read(parse_context_stack_t& context, bool store_hashes) if (! current.master) current.master = master; - count = read_textual(context, store_hashes); + count = read_textual(context, hash_type); if (count > 0) { if (! current.pathname.empty()) sources.push_back(fileinfo_t(current.pathname)); diff --git a/src/journal.h b/src/journal.h index d68618bf..cfc93c0a 100644 --- a/src/journal.h +++ b/src/journal.h @@ -184,7 +184,8 @@ public: return period_xacts.end(); } - std::size_t read(parse_context_stack_t& context, bool store_hashes); + std::size_t read(parse_context_stack_t& context, + hash_type_t hash_type); bool has_xdata(); void clear_xdata(); @@ -193,7 +194,8 @@ public: private: - std::size_t read_textual(parse_context_stack_t& context, bool store_hashes); + std::size_t read_textual(parse_context_stack_t& context, + hash_type_t hash_type); bool should_check_payees(); bool payee_not_registered(const string& name); diff --git a/src/precmd.cc b/src/precmd.cc index 25c28fc8..f90e8ced 100644 --- a/src/precmd.cc +++ b/src/precmd.cc @@ -74,7 +74,7 @@ namespace { parsing_context.get_current().journal = report.session.journal.get(); parsing_context.get_current().scope = &report.session; - report.session.journal->read(parsing_context, false); + report.session.journal->read(parsing_context, NO_HASHES); report.session.journal->clear_xdata(); } } diff --git a/src/session.cc b/src/session.cc index 4587f24a..f02ee9e9 100644 --- a/src/session.cc +++ b/src/session.cc @@ -134,7 +134,7 @@ std::size_t session_t::read_data(const string& master_account) parsing_context.push(*price_db_path); parsing_context.get_current().journal = journal.get(); try { - if (journal->read(parsing_context, HANDLED(hashes_)) > 0) + if (journal->read(parsing_context, HANDLER(hashes_).hash_type) > 0) throw_(parse_error, _("Transactions not allowed in price history file")); } catch (...) { @@ -169,7 +169,7 @@ std::size_t session_t::read_data(const string& master_account) parsing_context.get_current().journal = journal.get(); parsing_context.get_current().master = acct; try { - xact_count += journal->read(parsing_context, HANDLED(hashes_)); + xact_count += journal->read(parsing_context, HANDLER(hashes_).hash_type); } catch (...) { parsing_context.pop(); @@ -230,7 +230,7 @@ journal_t * session_t::read_journal_from_string(const string& data) parsing_context.get_current().journal = journal.get(); parsing_context.get_current().master = journal->master; try { - journal->read(parsing_context, HANDLED(hashes_)); + journal->read(parsing_context, HANDLER(hashes_).hash_type); } catch (...) { parsing_context.pop(); diff --git a/src/session.h b/src/session.h index ce1b69a3..c83be644 100644 --- a/src/session.h +++ b/src/session.h @@ -163,11 +163,6 @@ public: data_files.push_back(str); }); - enum hash_type_t { - NO_HASHES = 0, - HASH_SHA512 = 1 - }; - OPTION__ (session_t, hashes_, hash_type_t hash_type = NO_HASHES; @@ -175,6 +170,8 @@ public: DO_(str) { if (str == "sha512" || str == "SHA512") { hash_type = HASH_SHA512; + } else if (str == "sha512_256" || str == "SHA512_256") { + hash_type = HASH_SHA512_256; } else { throw_(std::invalid_argument, _f("Unrecognized hash type")); } diff --git a/src/textual.cc b/src/textual.cc index af208232..5488c6a3 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -40,6 +40,7 @@ #include "query.h" #include "pstream.h" #include "pool.h" +#include "session.h" #include <algorithm> #if HAVE_BOOST_PYTHON #include "pyinterp.h" @@ -79,7 +80,7 @@ namespace { instance_t * parent; std::list<application_t> apply_stack; bool no_assertions; - bool store_hashes; + hash_type_t hash_type; #if TIMELOG_SUPPORT time_log_t timelog; #endif @@ -88,10 +89,10 @@ namespace { parse_context_t& _context, instance_t * _parent = NULL, const bool _no_assertions = false, - const bool _store_hashes = false) + const hash_type_t _hash_type = NO_HASHES) : context_stack(_context_stack), context(_context), in(*context.stream.get()), parent(_parent), - no_assertions(_no_assertions), store_hashes(_store_hashes), + no_assertions(_no_assertions), hash_type(_hash_type), timelog(context) {} virtual string description() { @@ -805,7 +806,7 @@ void instance_t::include_directive(char * line) context_stack.get_current().scope = scope; try { instance_t instance(context_stack, context_stack.get_current(), - this, no_assertions, store_hashes); + this, no_assertions, hash_type); instance.apply_stack.push_front(application_t("account", master)); instance.parse(); } @@ -2020,11 +2021,12 @@ xact_t * instance_t::parse_xact(char * line, TRACE_STOP(xact_details, 1); - if (store_hashes) { + if (hash_type != NO_HASHES) { string expected_hash = xact->hash(previous_xact && previous_xact->has_tag("Hash") ? - previous_xact->get_tag("Hash")->to_string() : ""); + previous_xact->get_tag("Hash")->to_string() : "", + hash_type); if (xact->has_tag("Hash")) { string current_hash = xact->get_tag("Hash")->to_string(); if (! std::equal(expected_hash.begin(), @@ -2059,13 +2061,13 @@ expr_t::ptr_op_t instance_t::lookup(const symbol_t::kind_t kind, } std::size_t journal_t::read_textual(parse_context_stack_t& context_stack, - bool store_hashes) + hash_type_t hash_type) { TRACE_START(parsing_total, 1, "Total time spent parsing text:"); { instance_t instance(context_stack, context_stack.get_current(), NULL, checking_style == journal_t::CHECK_PERMISSIVE, - store_hashes); + hash_type); instance.apply_stack.push_front (application_t("account", context_stack.get_current().master)); instance.parse(); diff --git a/src/utils.h b/src/utils.h index c17c8fb1..34308807 100644 --- a/src/utils.h +++ b/src/utils.h @@ -605,6 +605,12 @@ inline string sha1sum(const string& str) extern const string version; +enum hash_type_t { + NO_HASHES = 0, + HASH_SHA512 = 1, + HASH_SHA512_256 = 2 +}; + } // namespace ledger /*@}*/ diff --git a/src/xact.cc b/src/xact.cc index 5c3c7042..ab53794a 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -594,7 +594,7 @@ namespace { } } -string xact_t::hash(string nonce) const { +string xact_t::hash(string nonce, hash_type_t hash_type) const { std::ostringstream repr; repr << nonce; repr << date(); @@ -621,7 +621,8 @@ string xact_t::hash(string nonce) const { unsigned char data[128]; string repr_str(repr.str()); SHA512((void *)repr_str.c_str(), repr_str.length(), data); - return bufferToHex(data, 64 /*SHA512_DIGEST_LENGTH*/); + return bufferToHex( + data, hash_type == HASH_SHA512 ? 64 : 32 /*SHA512_DIGEST_LENGTH*/); } namespace { @@ -128,7 +128,7 @@ public: virtual bool valid() const; - string hash(string nonce) const; + string hash(string nonce, hash_type_t hash_type) const; }; class auto_xact_t : public xact_base_t diff --git a/test/baseline/opt-hashes-sha512_256.test b/test/baseline/opt-hashes-sha512_256.test new file mode 100644 index 00000000..f269652d --- /dev/null +++ b/test/baseline/opt-hashes-sha512_256.test @@ -0,0 +1,28 @@ +2008/01/01 January + Expenses:Books $10.00 + Assets:Cash + +2008/01/31 End of January + Expenses:Books $10.00 + Assets:Cash + +2008/02/01 February + Assets:Cash + Expenses:Books $20.00 + +test print --hashes=sha512_256 +2008/01/01 January + ; Hash: c0f3322857def0d32bd2c9398e0785aacc8206f9ba64ef923978cbdcea13f59c + Expenses:Books $10.00 + Assets:Cash + +2008/01/31 End of January + ; Hash: 151aa236cc3c632e492a94739d92fa76f321939dac04102b4c5ef893384ac839 + Expenses:Books $10.00 + Assets:Cash + +2008/02/01 February + ; Hash: 0336590b40e1fc83d6ade4a8c8e8f1c75af10deaac2be80580fbb73b0086324d + Assets:Cash + Expenses:Books $20.00 +end test |