diff --git a/third_party/zxcvbn-cpp/data-scripts/build_keyboard_adjacency_graphs.py b/third_party/zxcvbn-cpp/data-scripts/build_keyboard_adjacency_graphs.py
index 8135c697ed2f..605f2d6d18bd 100755
--- a/third_party/zxcvbn-cpp/data-scripts/build_keyboard_adjacency_graphs.py
+++ b/third_party/zxcvbn-cpp/data-scripts/build_keyboard_adjacency_graphs.py
@@ -90,6 +90,14 @@ def build_graph(layout_str, slanted):
                 adjacency_graph[char].append(position_table.get(coord, None))
     return adjacency_graph
 
+# on qwerty, 'g' has degree 6, being adjacent to 'ftyhbv'. '\' has degree 1.
+# this calculates the average over all keys.
+def calc_average_deg_and_len(layout_str, slanted):
+  graph = build_graph(layout_str, slanted)
+  count = sum(a is not None for adj in graph.values() for a in adj)
+  length = len(graph)
+  return float(count) / length, length
+
 GRAPHS = [('qwerty', (qwerty, True)),
           ('dvorak', (dvorak, True)),
           ('keypad', (keypad, False)),
@@ -127,6 +135,8 @@ def output_hpp(hpp_file):
 #include <utility>
 #include <vector>
 
+#include "base/strings/string_piece.h"
+
 namespace zxcvbn {
 
 enum class GraphTag {
@@ -148,7 +158,7 @@ struct hash<zxcvbn::GraphTag> {
 
 namespace zxcvbn {
 
-using Graph = std::unordered_map<std::string, std::vector<optional::optional<std::string>>>;
+using Graph = std::unordered_map<base::StringPiece, std::vector<base::StringPiece>, base::StringPieceHash>;
 using Graphs = std::unordered_map<GraphTag, Graph>;
 const Graphs & graphs();
 
@@ -167,71 +177,47 @@ extern const std::size_t KEYPAD_STARTING_POSITIONS;
 
 def output_cpp(cpp_file):
     with open(cpp_file, 'w') as f:
-        f.write('// generated by scripts/build_keyboard_adjacency_graphs.py\n')
-        f.write("#include <zxcvbn/adjacency_graphs.hpp>\n\n")
-        f.write("#include <zxcvbn/optional.hpp>\n\n")
-        f.write("#include <array>\n")
-        f.write("#include <initializer_list>\n")
-        f.write("#include <utility>\n\n")
+        f.write("""// generated by scripts/build_keyboard_adjacency_graphs.py
+#include <zxcvbn/adjacency_graphs.hpp>
 
-        # find out largest adjacency_list
-        largest = max(len(adj)
-                      for (_, args2) in GRAPHS
-                      for adj in build_graph(*args2).values())
+#include <array>
+#include <initializer_list>
+#include <utility>
 
+#include "base/no_destructor.h"
+
+""")
+
+        qwerty_avg_deg, qwerty_len = calc_average_deg_and_len(qwerty, True)
+        keypad_avg_deg, keypad_len = calc_average_deg_and_len(keypad, False)
         f.write("""namespace zxcvbn {
 
-static
-optional::optional<std::string> M(const char *s) {
-  return optional::make_optional(std::string(s));
-}
+extern constexpr degree_t KEYBOARD_AVERAGE_DEGREE = %f;
+// slightly different for keypad/mac keypad, but close enough
+extern constexpr degree_t KEYPAD_AVERAGE_DEGREE = %f;
 
-const auto no = optional::nullopt;
+extern constexpr std::size_t KEYBOARD_STARTING_POSITIONS = %d;
+extern constexpr std::size_t KEYPAD_STARTING_POSITIONS = %d;
 
-""")
+""" % (qwerty_avg_deg, keypad_avg_deg, qwerty_len, keypad_len))
 
-        f.write("const Graphs _graphs = {\n")
+        f.write("const Graphs& graphs() {\n")
+        f.write("  static base::NoDestructor<Graphs> graphs({\n")
         for (name, args2) in GRAPHS:
             graph = build_graph(*args2)
 
-            f.write("  {GraphTag::%s, {\n" % (name.upper(),));
+            f.write("    {GraphTag::%s, {\n" % (name.upper(),));
 
             for key, adj in sorted(graph.items()):
-                f.write('    {"%s", {%s}},\n' %
-                        (escape(key), ', '.join('M("' + escape(a) + '")'
+                f.write('      {"%s", {%s}},\n' %
+                        (escape(key), ', '.join('"' + escape(a) + '"'
                                                 if a else
-                                                'no'
+                                                '{}'
                                                 for a in adj)))
-            f.write("  }},\n")
-
-        f.write("""};
-
-// on qwerty, 'g' has degree 6, being adjacent to 'ftyhbv'. '\' has degree 1.
-// this calculates the average over all keys.
-static
-degree_t calc_average_degree(const Graph & graph)  {
-  degree_t average = 0;
-  for (const auto & item : graph) {
-    for (const auto & neighbor : item.second) {
-        average += neighbor ? 1 : 0;
-    }
-  }
-  average /= graph.size();
-  return average;
-}
-
-extern const degree_t KEYBOARD_AVERAGE_DEGREE = calc_average_degree(_graphs.at(GraphTag::QWERTY));
-// slightly different for keypad/mac keypad, but close enough
-extern const degree_t KEYPAD_AVERAGE_DEGREE = calc_average_degree(_graphs.at(GraphTag::KEYPAD));
-
-extern const std::size_t KEYBOARD_STARTING_POSITIONS = _graphs.at(GraphTag::QWERTY).size();
-extern const std::size_t KEYPAD_STARTING_POSITIONS = _graphs.at(GraphTag::KEYPAD).size();
-
-const Graphs & graphs() {
-  return _graphs;
-}
-
-""")
+            f.write("    }},\n")
+        f.write("  });\n\n")
+        f.write("  return *graphs;\n")
+        f.write("}\n\n")
         f.write("}\n")
 
 
diff --git a/third_party/zxcvbn-cpp/native-src/zxcvbn/matching.cpp b/third_party/zxcvbn-cpp/native-src/zxcvbn/matching.cpp
index 173382e70626..c14e02618ec2 100644
--- a/third_party/zxcvbn-cpp/native-src/zxcvbn/matching.cpp
+++ b/third_party/zxcvbn-cpp/native-src/zxcvbn/matching.cpp
@@ -381,7 +381,7 @@ std::vector<Match> spatial_match_helper(const std::string & password,
         if (it != graph.end()) {
           return it->second;
         }
-        return std::vector<optional::optional<std::string>>();
+        return Graph::mapped_type();
       }();
       // consider growing pattern by one character if j hasn't gone over the edge.
       if (j < clen) {
@@ -390,10 +390,10 @@ std::vector<Match> spatial_match_helper(const std::string & password,
         auto cur_char = password.substr(jdx, next_jdx - jdx);
         for (auto & adj : adjacents) {
           cur_direction += 1;
-          if (adj && adj->find(cur_char) != adj->npos) {
+          if (adj.find(cur_char) != adj.npos) {
             found = true;
             found_direction = cur_direction;
-            if (adj->find(cur_char) == 1) {
+            if (adj.find(cur_char) == 1) {
               // index 1 in the adjacency means the key is shifted,
               // 0 means unshifted: A vs a, % vs 5, etc.
               // for example, 'q' is adjacent to the entry '2@'.