Device interface library for multiple platforms including Mbed.

Dependents:   DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#

Maxim Interface is a library framework focused on providing flexible and expressive hardware interfaces. Both communication interfaces such as I2C and 1-Wire and device interfaces such as DS18B20 are supported. Modern C++ concepts are used extensively while keeping compatibility with C++98/C++03 and requiring no external dependencies. The embedded-friendly design does not depend on exceptions or RTTI.

The full version of the project is hosted on GitLab: https://gitlab.com/iabenz/MaximInterface

Revision:
8:5ea891c7d1a1
Parent:
7:9cd16581b578
Child:
11:3f3bf6bf5e6c
--- a/MaximInterfaceDevices/DS28C36_DS2476.cpp	Mon Jul 22 11:44:07 2019 -0500
+++ b/MaximInterfaceDevices/DS28C36_DS2476.cpp	Mon Sep 16 11:13:37 2019 -0500
@@ -1,5 +1,5 @@
 /*******************************************************************************
-* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
@@ -36,21 +36,22 @@
 #include <MaximInterfaceCore/RomId.hpp>
 #include "DS28C36_DS2476.hpp"
 
+#define TRY MaximInterfaceCore_TRY
+#define TRY_VALUE MaximInterfaceCore_TRY_VALUE
+
 namespace MaximInterfaceDevices {
 
 using namespace Core;
 using namespace Ecc256;
 using std::copy;
 
-static error_code convertResultByte(uint_least8_t resultByte) {
-  error_code errorCode;
-  if (resultByte != 0xAA) {
-    errorCode.assign((resultByte == 0x00)
-                         ? static_cast<int>(DS28C36::AuthenticationError)
-                         : resultByte,
-                     DS28C36::errorCategory());
-  }
-  return errorCode;
+static Result<void> convertResultByte(uint_least8_t resultByte) {
+  return (resultByte == 0xAA)
+             ? makeResult(none)
+             : error_code((resultByte == 0x00)
+                              ? static_cast<int>(DS28C36::AuthenticationError)
+                              : resultByte,
+                          DS28C36::errorCategory());
 }
 
 const int DS28C36::publicKeyAxPage;
@@ -71,166 +72,178 @@
 const int DS28C36::publicKeySyPage;
 const int DS28C36::memoryPages;
 
-error_code DS28C36::writeMemory(int pageNum, Page::const_span page) {
+Result<void> DS28C36::writeMemory(int pageNum, Page::const_span page) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[1 + Page::size];
   buffer[0] = pageNum;
   copy(page.begin(), page.end(), buffer + 1);
-  error_code result = writeCommand(0x96, buffer);
+  Result<void> result = writeCommand(0x96, buffer);
   if (!result) {
-    sleep(writeMemoryTimeMs);
-    result = readFixedLengthResponse(make_span(buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer[0]);
-    }
+    return result;
   }
+  sleep(writeMemoryTimeMs);
+  result = readFixedLengthResponse(make_span(buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer[0]);
   return result;
 }
 
-error_code DS28C36::readMemory(int pageNum, Page::span page) {
+Result<DS28C36::Page::array> DS28C36::readMemory(int pageNum) const {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const uint_least8_t parameter = pageNum;
-  error_code result = writeCommand(0x69, make_span(&parameter, 1));
+  Result<void> result = writeCommand(0x69, make_span(&parameter, 1));
+  if (!result) {
+    return result.error();
+  }
+  sleep(readMemoryTimeMs);
+  array<uint_least8_t, 1 + Page::size> response;
+  result = readFixedLengthResponse(response);
   if (!result) {
-    sleep(readMemoryTimeMs);
-    array<uint_least8_t, 1 + Page::size> response;
-    result = readFixedLengthResponse(response);
-    if (!result) {
-      result = convertResultByte(response[0]);
-      copy(response.begin() + 1, response.end(), page.begin());
-    }
+    return result.error();
   }
-  return result;
+  result = convertResultByte(response[0]);
+  if (!result) {
+    return result.error();
+  }
+  Page::array page;
+  copy(response.begin() + 1, response.end(), page.begin());
+  return page;
 }
 
-error_code DS28C36::writeBuffer(span<const uint_least8_t> data) {
+Result<void> DS28C36::writeBuffer(span<const uint_least8_t> data) {
   return writeCommand(0x87, data);
 }
 
-error_code DS28C36::readBuffer(std::vector<uint_least8_t> & data) {
-  error_code result = writeCommand(0x5A);
-  if (!result) {
-    data.resize(80);
-    span<uint_least8_t> dataSpan(data);
-    result = readVariableLengthResponse(dataSpan);
-    if (result) {
-      data.clear();
-    } else {
-      data.resize(dataSpan.size());
-    }
-  }
-  return result;
+Result<std::vector<uint_least8_t> > DS28C36::readBuffer() const {
+  TRY(writeCommand(0x5A));
+  std::vector<uint_least8_t> buffer(80);
+  span<uint_least8_t>::index_type bufferLength;
+  TRY_VALUE(bufferLength, readVariableLengthResponse(buffer));
+  buffer.resize(bufferLength);
+  return buffer;
 }
 
-error_code DS28C36::readPageProtection(int pageNum,
-                                       PageProtection & protection) {
+Result<DS28C36::PageProtection> DS28C36::readPageProtection(int pageNum) const {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer = pageNum;
-  error_code result = writeCommand(0xAA, make_span(&buffer, 1));
+  Result<void> result = writeCommand(0xAA, make_span(&buffer, 1));
   if (!result) {
-    sleep(readMemoryTimeMs);
-    result = readFixedLengthResponse(make_span(&buffer, 1));
-    if (!result) {
-      protection = buffer;
-    }
+    return result.error();
   }
-  return result;
+  sleep(readMemoryTimeMs);
+  result = readFixedLengthResponse(make_span(&buffer, 1));
+  if (!result) {
+    return result.error();
+  }
+  return PageProtection(buffer);
 }
 
-error_code DS28C36::setPageProtection(int pageNum,
-                                      const PageProtection & protection) {
+Result<void> DS28C36::setPageProtection(int pageNum,
+                                        const PageProtection & protection) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[] = {static_cast<uint_least8_t>(pageNum),
                             static_cast<uint_least8_t>(protection.to_ulong())};
-  error_code result = writeCommand(0xC3, buffer);
+  Result<void> result = writeCommand(0xC3, buffer);
   if (!result) {
-    sleep(writeMemoryTimeMs);
-    result = readFixedLengthResponse(make_span(buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer[0]);
-    }
+    return result;
   }
+  sleep(writeMemoryTimeMs);
+  result = readFixedLengthResponse(make_span(buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer[0]);
   return result;
 }
 
-error_code DS28C36::decrementCounter() {
-  error_code result = writeCommand(0xC9);
+Result<void> DS28C36::decrementCounter() {
+  Result<void> result = writeCommand(0xC9);
   if (!result) {
-    sleep(writeMemoryTimeMs);
-    uint_least8_t response;
-    result = readFixedLengthResponse(make_span(&response, 1));
-    if (!result) {
-      result = convertResultByte(response);
-    }
+    return result;
   }
+  sleep(writeMemoryTimeMs);
+  uint_least8_t response;
+  result = readFixedLengthResponse(make_span(&response, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(response);
   return result;
 }
 
-error_code DS28C36::readRng(span<uint_least8_t> data) {
+Result<void> DS28C36::readRng(span<uint_least8_t> data) const {
   if ((data.size() < 1) || (data.size() > 64)) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   data[0] = static_cast<uint_least8_t>(data.size() - 1);
-  error_code result = writeCommand(0xD2, data.first(1));
+  Result<void> result = writeCommand(0xD2, data.first(1));
   if (!result) {
-    sleep(sha256ComputationTimeMs);
-    result = readFixedLengthResponse(data);
+    return result;
   }
+  sleep(sha256ComputationTimeMs);
+  result = readFixedLengthResponse(data);
   return result;
 }
 
-error_code DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum,
-                                        EncryptionChallenge::span challenge,
-                                        Page::span data) {
+Result<std::pair<DS28C36::EncryptionChallenge::array, DS28C36::Page::array> >
+DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum) const {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const uint_least8_t parameter = (secretNum << 6) | pageNum;
-  error_code result = writeCommand(0x4B, make_span(&parameter, 1));
+  Result<void> result = writeCommand(0x4B, make_span(&parameter, 1));
+  if (!result) {
+    return result.error();
+  }
+  sleep(readMemoryTimeMs + sha256ComputationTimeMs);
+  uint_least8_t response[1 + EncryptionChallenge::size + Page::size];
+  result = readFixedLengthResponse(response);
   if (!result) {
-    sleep(readMemoryTimeMs + sha256ComputationTimeMs);
-    uint_least8_t response[1 + EncryptionChallenge::size + Page::size];
-    result = readFixedLengthResponse(response);
-    if (!result) {
-      result = convertResultByte(response[0]);
-      const uint_least8_t * begin = response + 1;
-      const uint_least8_t * end = begin + challenge.size();
-      copy(begin, end, challenge.begin());
-      begin = end;
-      end = begin + data.size();
-      copy(begin, end, data.begin());
-    }
+    return result.error();
+  }
+  result = convertResultByte(response[0]);
+  if (!result) {
+    return result.error();
   }
-  return result;
+  std::pair<DS28C36::EncryptionChallenge::array, DS28C36::Page::array> data;
+  const uint_least8_t * begin = response + 1;
+  const uint_least8_t * end = begin + data.first.size();
+  copy(begin, end, data.first.begin());
+  begin = end;
+  end = begin + data.second.size();
+  copy(begin, end, data.second.begin());
+  return data;
 }
 
-error_code DS28C36::computeAndReadPageAuthentication(int pageNum,
-                                                     AuthType authType) {
+Result<void>
+DS28C36::computeAndReadPageAuthentication(int pageNum,
+                                          AuthType authType) const {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const uint_least8_t parameter = (authType << 5) | pageNum;
   return writeCommand(0xA5, make_span(&parameter, 1));
 }
 
-error_code
-DS28C36::computeAndReadPageAuthentication(int pageNum, KeyNum keyNum,
-                                          Signature::span signature) {
+Result<Signature::array>
+DS28C36::computeAndReadPageAuthentication(int pageNum, KeyNum keyNum) const {
   AuthType authType;
   switch (keyNum) {
   case KeyNumA:
@@ -243,29 +256,35 @@
     authType = EcdsaWithKeyC;
     break;
   default:
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
-  error_code result = computeAndReadPageAuthentication(pageNum, authType);
+  Result<void> result = computeAndReadPageAuthentication(pageNum, authType);
+  if (!result) {
+    return result.error();
+  }
+  sleep(readMemoryTimeMs + generateEcdsaSignatureTimeMs);
+  uint_least8_t response[1 + 2 * Scalar::size];
+  result = readFixedLengthResponse(response);
   if (!result) {
-    sleep(readMemoryTimeMs + generateEcdsaSignatureTimeMs);
-    uint_least8_t response[1 + 2 * Scalar::size];
-    result = readFixedLengthResponse(response);
-    if (!result) {
-      result = convertResultByte(response[0]);
-      const uint_least8_t * begin = response + 1;
-      const uint_least8_t * end = begin + signature.s.size();
-      copy(begin, end, signature.s.begin());
-      begin = end;
-      end = begin + signature.r.size();
-      copy(begin, end, signature.r.begin());
-    }
+    return result.error();
+  }
+  result = convertResultByte(response[0]);
+  if (!result) {
+    return result.error();
   }
-  return result;
+  Signature::array signature;
+  const uint_least8_t * begin = response + 1;
+  const uint_least8_t * end = begin + signature.s.size();
+  copy(begin, end, signature.s.begin());
+  begin = end;
+  end = begin + signature.r.size();
+  copy(begin, end, signature.r.begin());
+  return signature;
 }
 
-error_code DS28C36::computeAndReadPageAuthentication(int pageNum,
-                                                     SecretNum secretNum,
-                                                     Page::span hmac) {
+Result<DS28C36::Page::array>
+DS28C36::computeAndReadPageAuthentication(int pageNum,
+                                          SecretNum secretNum) const {
   AuthType authType;
   switch (secretNum) {
   case SecretNumA:
@@ -278,93 +297,106 @@
     authType = HmacWithSecretS;
     break;
   default:
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
-  error_code result = computeAndReadPageAuthentication(pageNum, authType);
+  Result<void> result = computeAndReadPageAuthentication(pageNum, authType);
+  if (!result) {
+    return result.error();
+  }
+  sleep(readMemoryTimeMs + sha256ComputationTimeMs);
+  array<uint_least8_t, 1 + Page::size> response;
+  result = readFixedLengthResponse(response);
   if (!result) {
-    sleep(readMemoryTimeMs + sha256ComputationTimeMs);
-    array<uint_least8_t, 1 + Page::size> response;
-    result = readFixedLengthResponse(response);
-    if (!result) {
-      result = convertResultByte(response[0]);
-      copy(response.begin() + 1, response.end(), hmac.begin());
-    }
+    return result.error();
   }
-  return result;
+  result = convertResultByte(response[0]);
+  if (!result) {
+    return result.error();
+  }
+  Page::array hmac;
+  copy(response.begin() + 1, response.end(), hmac.begin());
+  return hmac;
 }
 
-error_code DS28C36::authenticatedSha2WriteMemory(int pageNum,
-                                                 SecretNum secretNum,
-                                                 Page::const_span page) {
+Result<void> DS28C36::authenticatedSha2WriteMemory(int pageNum,
+                                                   SecretNum secretNum,
+                                                   Page::const_span page) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[1 + Page::size];
   buffer[0] = (secretNum << 6) | pageNum;
   copy(page.begin(), page.end(), buffer + 1);
-  error_code result = writeCommand(0x99, buffer);
+  Result<void> result = writeCommand(0x99, buffer);
   if (!result) {
-    sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs));
-    result = readFixedLengthResponse(make_span(buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer[0]);
-    }
+    return result;
   }
+  sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs));
+  result = readFixedLengthResponse(make_span(buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer[0]);
   return result;
 }
 
-error_code DS28C36::computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
-                                             SecretNum dsecretNum,
-                                             bool writeProtectEnable) {
+Result<void> DS28C36::computeAndLockSha2Secret(int pageNum,
+                                               SecretNum msecretNum,
+                                               SecretNum dsecretNum,
+                                               bool writeProtectEnable) {
   // User pages only
   if (pageNum < 0 || pageNum > 15) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[] = {
       static_cast<uint_least8_t>((dsecretNum << 6) | (msecretNum << 4) |
                                  pageNum),
       static_cast<uint_least8_t>(writeProtectEnable ? 0x80 : 0x00)};
-  error_code result = writeCommand(0x3C, buffer);
+  Result<void> result = writeCommand(0x3C, buffer);
   if (!result) {
-    sleep(sha256ComputationTimeMs +
-          ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs));
-    result = readFixedLengthResponse(make_span(buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer[0]);
-    }
+    return result;
   }
+  sleep(sha256ComputationTimeMs +
+        ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs));
+  result = readFixedLengthResponse(make_span(buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer[0]);
   return result;
 }
 
-error_code DS28C36::generateEcc256KeyPair(KeyNum keyNum,
-                                          bool writeProtectEnable) {
+Result<void> DS28C36::generateEcc256KeyPair(KeyNum keyNum,
+                                            bool writeProtectEnable) {
   if (keyNum == KeyNumS) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer = keyNum;
   if (writeProtectEnable) {
     buffer |= 0x80;
   }
-  error_code result = writeCommand(0xCB, make_span(&buffer, 1));
+  Result<void> result = writeCommand(0xCB, make_span(&buffer, 1));
   if (!result) {
-    sleep(generateEccKeyPairTimeMs);
-    result = readFixedLengthResponse(make_span(&buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer);
-    }
+    return result;
   }
+  sleep(generateEccKeyPairTimeMs);
+  result = readFixedLengthResponse(make_span(&buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer);
   return result;
 }
 
-error_code DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock,
-                                          span<const uint_least8_t> data) {
+Result<void> DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock,
+                                            span<const uint_least8_t> data) {
   const span<const uint_least8_t>::index_type maxDataSize = 64;
 
   if (data.size() < 1 || data.size() > maxDataSize) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[1 + maxDataSize];
@@ -376,20 +408,22 @@
     buffer[0] |= 0x80;
   }
   copy(data.begin(), data.end(), buffer + 1);
-  error_code result = writeCommand(0x33, make_span(buffer, data.size() + 1));
+  Result<void> result = writeCommand(0x33, make_span(buffer, data.size() + 1));
   if (!result) {
-    sleep(sha256ComputationTimeMs);
-    result = readFixedLengthResponse(make_span(buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer[0]);
-    }
+    return result;
   }
+  sleep(sha256ComputationTimeMs);
+  result = readFixedLengthResponse(make_span(buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer[0]);
   return result;
 }
 
-error_code DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
-                                         Signature::const_span signature,
-                                         PioState pioa, PioState piob) {
+Result<void> DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
+                                           Signature::const_span signature,
+                                           PioState pioa, PioState piob) {
   uint_least8_t buffer[1 + 2 * Scalar::size];
   buffer[0] = keyNum | (hashType << 2);
   if (pioa != Unchanged) {
@@ -407,25 +441,27 @@
   uint_least8_t * bufferIt =
       copy(signature.r.begin(), signature.r.end(), buffer + 1);
   copy(signature.s.begin(), signature.s.end(), bufferIt);
-  error_code result = writeCommand(0x59, buffer);
+  Result<void> result = writeCommand(0x59, buffer);
   if (!result) {
-    sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs +
-          ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0));
-    result = readFixedLengthResponse(make_span(buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer[0]);
-    }
+    return result;
   }
+  sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs +
+        ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0));
+  result = readFixedLengthResponse(make_span(buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer[0]);
   return result;
 }
 
-error_code
+Result<void>
 DS28C36::authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum,
                                     int csOffset,
                                     Signature::const_span signature) {
   if (((keyNum != KeyNumA) && (keyNum != KeyNumB)) || (csOffset < 0) ||
       (csOffset > 31)) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[1 + 2 * Scalar::size];
@@ -439,58 +475,62 @@
   uint_least8_t * bufferIt =
       copy(signature.r.begin(), signature.r.end(), buffer + 1);
   copy(signature.s.begin(), signature.s.end(), bufferIt);
-  error_code result = writeCommand(0xA8, buffer);
+  Result<void> result = writeCommand(0xA8, buffer);
   if (!result) {
-    sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs);
-    result = readFixedLengthResponse(make_span(buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer[0]);
-    }
+    return result;
   }
+  sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs);
+  result = readFixedLengthResponse(make_span(buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer[0]);
   return result;
 }
 
-error_code DS28C36::authenticatedEcdsaWriteMemory(int pageNum,
-                                                  Page::const_span page) {
+Result<void> DS28C36::authenticatedEcdsaWriteMemory(int pageNum,
+                                                    Page::const_span page) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[1 + Page::size];
   buffer[0] = pageNum;
   copy(page.begin(), page.end(), buffer + 1);
-  error_code result = writeCommand(0x89, buffer);
+  Result<void> result = writeCommand(0x89, buffer);
   if (!result) {
-    sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs +
-          sha256ComputationTimeMs);
-    result = readFixedLengthResponse(make_span(buffer, 1));
-    if (!result) {
-      result = convertResultByte(buffer[0]);
-    }
+    return result;
   }
+  sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs +
+        sha256ComputationTimeMs);
+  result = readFixedLengthResponse(make_span(buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer[0]);
   return result;
 }
 
-error_code DS28C36::writeCommand(uint_least8_t command,
-                                 span<const uint_least8_t> parameters) {
-  error_code result = master->start(address_);
-  if (result) {
+Result<void> DS28C36::writeCommand(uint_least8_t command,
+                                   span<const uint_least8_t> parameters) const {
+  Result<void> result = master->start(address_);
+  if (!result) {
     master->stop();
     return result;
   }
   result = master->writeByte(command);
-  if (result) {
+  if (!result) {
     master->stop();
     return result;
   }
   if (!parameters.empty()) {
     result = master->writeByte(static_cast<uint_least8_t>(parameters.size()));
-    if (result) {
+    if (!result) {
       master->stop();
       return result;
     }
     result = master->writeBlock(parameters);
-    if (result) {
+    if (!result) {
       master->stop();
       return result;
     }
@@ -499,41 +539,44 @@
   return result;
 }
 
-error_code DS28C36::readVariableLengthResponse(span<uint_least8_t> & response) {
-  error_code result = master->start(address_ | 1);
-  if (result) {
+Result<span<uint_least8_t>::index_type>
+DS28C36::readVariableLengthResponse(span<uint_least8_t> response) const {
+  Result<void> result = master->start(address_ | 1);
+  if (!result) {
     master->stop();
-    return result;
+    return result.error();
   }
   uint_least8_t length;
-  result = master->readByte(I2CMaster::Ack, length);
-  if (result) {
+  if (const Result<uint_least8_t> result = master->readByte(I2CMaster::Ack)) {
+    length = result.value();
+  } else {
     master->stop();
-    return result;
+    return result.error();
   }
   if (length > response.size()) {
     master->stop();
-    return make_error_code(InvalidResponseError);
+    return InvalidResponseError;
   }
-  response = response.first(length);
-  if (!response.empty()) {
-    result = master->readBlock(I2CMaster::Nack, response);
-    if (result) {
+  if (length > 0) {
+    result = master->readBlock(response.first(length), I2CMaster::Nack);
+    if (!result) {
       master->stop();
-      return result;
+      return result.error();
     }
   }
   result = master->stop();
-  return result;
+  if (!result) {
+    return result.error();
+  }
+  return length;
 }
 
-error_code DS28C36::readFixedLengthResponse(span<uint_least8_t> response) {
-  const span<uint_least8_t>::index_type requestedResponseSize = response.size();
-  error_code result = readVariableLengthResponse(response);
-  if (!result && response.size() != requestedResponseSize) {
-    result = make_error_code(InvalidResponseError);
-  }
-  return result;
+Result<void>
+DS28C36::readFixedLengthResponse(span<uint_least8_t> response) const {
+  span<uint_least8_t>::index_type responseLength;
+  TRY_VALUE(responseLength, readVariableLengthResponse(response));
+  return (responseLength == response.size()) ? makeResult(none)
+                                             : InvalidResponseError;
 }
 
 const error_category & DS28C36::errorCategory() {
@@ -560,151 +603,146 @@
 
       case InvalidResponseError:
         return "Invalid Response Error";
-
-      default:
-        return defaultErrorMessage(condition);
       }
+      return defaultErrorMessage(condition);
     }
   } instance;
   return instance;
 }
 
-error_code DS2476::generateEcdsaSignature(KeyNum keyNum,
-                                          Signature::span signature) {
+Result<Signature::array> DS2476::generateEcdsaSignature(KeyNum keyNum) const {
   if (keyNum == KeyNumS) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const uint_least8_t parameter = keyNum;
-  error_code result = writeCommand(0x1E, make_span(&parameter, 1));
+  Result<void> result = writeCommand(0x1E, make_span(&parameter, 1));
+  if (!result) {
+    return result.error();
+  }
+  sleep(generateEcdsaSignatureTimeMs);
+  uint_least8_t response[1 + 2 * Scalar::size];
+  result = readFixedLengthResponse(response);
+  if (!result) {
+    return result.error();
+  }
+  result = convertResultByte(response[0]);
   if (!result) {
-    sleep(generateEcdsaSignatureTimeMs);
-    uint_least8_t response[1 + 2 * Scalar::size];
-    result = readFixedLengthResponse(response);
-    if (!result) {
-      result = convertResultByte(response[0]);
-      const uint_least8_t * begin = response + 1;
-      const uint_least8_t * end = begin + signature.s.size();
-      copy(begin, end, signature.s.begin());
-      begin = end;
-      end = begin + signature.r.size();
-      copy(begin, end, signature.r.begin());
-    }
+    return result.error();
   }
+  Signature::array signature;
+  const uint_least8_t * begin = response + 1;
+  const uint_least8_t * end = begin + signature.s.size();
+  copy(begin, end, signature.s.begin());
+  begin = end;
+  end = begin + signature.r.size();
+  copy(begin, end, signature.r.begin());
+  return signature;
+}
+
+Result<void> DS2476::computeSha2UniqueSecret(SecretNum msecretNum) {
+  uint_least8_t buffer = msecretNum << 4;
+  Result<void> result = writeCommand(0x55, make_span(&buffer, 1));
+  if (!result) {
+    return result;
+  }
+  sleep(sha256ComputationTimeMs);
+  result = readFixedLengthResponse(make_span(&buffer, 1));
+  if (!result) {
+    return result;
+  }
+  result = convertResultByte(buffer);
   return result;
 }
 
-error_code DS2476::computeSha2UniqueSecret(SecretNum msecretNum) {
-  uint_least8_t buffer = msecretNum << 4;
-  error_code result = writeCommand(0x55, make_span(&buffer, 1));
+Result<DS2476::Page::array> DS2476::computeSha2Hmac() const {
+  Result<void> result = writeCommand(0x2D);
+  if (!result) {
+    return result.error();
+  }
+  sleep(sha256ComputationTimeMs);
+  array<uint_least8_t, 1 + Page::size> response;
+  result = readFixedLengthResponse(response);
   if (!result) {
-    sleep(sha256ComputationTimeMs);
-    result = readFixedLengthResponse(make_span(&buffer, 1));
-    if (!result) {
-      convertResultByte(buffer);
-    }
+    return result.error();
   }
-  return result;
+  result = convertResultByte(response[0]);
+  if (!result) {
+    return result.error();
+  }
+  Page::array hmac;
+  copy(response.begin() + 1, response.end(), hmac.begin());
+  return hmac;
 }
 
-error_code DS2476::computeSha2Hmac(Page::span hmac) {
-  error_code result = writeCommand(0x2D);
-  if (!result) {
-    sleep(sha256ComputationTimeMs);
-    array<uint_least8_t, 1 + Page::size> response;
-    result = readFixedLengthResponse(response);
-    if (!result) {
-      result = convertResultByte(response[0]);
-      copy(response.begin() + 1, response.end(), hmac.begin());
-    }
-  }
-  return result;
-}
-
-error_code computeMultiblockHash(DS28C36 & ds28c36,
-                                 span<const uint_least8_t> data) {
-  error_code result;
+Result<void> computeMultiblockHash(DS28C36 & ds28c36,
+                                   span<const uint_least8_t> data) {
   span<const uint_least8_t>::index_type dataIdx = 0;
-  while (dataIdx < data.size() && !result) {
+  while (dataIdx < data.size()) {
     const span<const uint_least8_t>::index_type remainingSize =
         data.size() - dataIdx;
     const span<const uint_least8_t>::index_type chunkSize =
         std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
-    result =
-        ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
-                                      data.subspan(dataIdx, chunkSize));
+    TRY(ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
+                                      data.subspan(dataIdx, chunkSize)));
     dataIdx += chunkSize;
   }
-  return result;
+  return none;
 }
 
-error_code verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
-                                span<const uint_least8_t> data,
-                                Signature::const_span signature,
-                                DS28C36::PioState pioa,
-                                DS28C36::PioState piob) {
-  error_code result = computeMultiblockHash(ds28c36, data);
-  if (!result) {
+Result<void> verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
+                                  span<const uint_least8_t> data,
+                                  Signature::const_span signature,
+                                  DS28C36::PioState pioa,
+                                  DS28C36::PioState piob) {
+  Result<void> result = computeMultiblockHash(ds28c36, data);
+  if (result) {
     result = ds28c36.verifyEcdsaSignature(publicKey, DS28C36::THASH, signature,
                                           pioa, piob);
   }
   return result;
 }
 
-error_code verifyEcdsaSignature(DS28C36 & ds28c36,
-                                PublicKey::const_span publicKey,
-                                span<const uint_least8_t> data,
-                                Signature::const_span signature,
-                                DS28C36::PioState pioa,
-                                DS28C36::PioState piob) {
-  error_code result =
+Result<void> verifyEcdsaSignature(DS28C36 & ds28c36,
+                                  PublicKey::const_span publicKey,
+                                  span<const uint_least8_t> data,
+                                  Signature::const_span signature,
+                                  DS28C36::PioState pioa,
+                                  DS28C36::PioState piob) {
+  Result<void> result =
       ds28c36.writeMemory(DS28C36::publicKeySxPage, publicKey.x);
   if (!result) {
-    result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y);
+    return result;
   }
+  result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y);
   if (!result) {
-    result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, signature,
-                                  pioa, piob);
+    return result;
   }
+  result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, signature,
+                                pioa, piob);
   return result;
 }
 
-error_code readRomIdAndManId(DS28C36 & ds28c36, RomId::span romId,
-                             ManId::span manId) {
-  DS28C36::Page::array page;
-  error_code result = ds28c36.readMemory(DS28C36::romOptionsPage, page);
-  if (!result) {
-    const DS28C36::RomOptions romOptions(page);
-    copy(romOptions.romId(), romId);
-    copy(romOptions.manId(), manId);
+Result<void> enableCoprocessor(DS2476 & ds2476) {
+  DS2476::Page::array page;
+  TRY_VALUE(page, ds2476.readMemory(DS2476::gpioControlPage));
+  DS2476::GpioControl gpioControl(page);
+  if (!gpioControl.pioaConducting()) {
+    gpioControl.setPioaConducting(true);
+    TRY(ds2476.writeMemory(DS2476::gpioControlPage, page));
   }
-  return result;
+  return none;
 }
 
-error_code enableCoprocessor(DS2476 & ds2476) {
+Result<void> enableRomId(DS2476 & ds2476) {
   DS2476::Page::array page;
-  error_code result = ds2476.readMemory(DS2476::gpioControlPage, page);
-  if (!result) {
-    DS2476::GpioControl gpioControl(page);
-    if (!gpioControl.pioaConducting()) {
-      gpioControl.setPioaConducting(true);
-      result = ds2476.writeMemory(DS2476::gpioControlPage, page);
-    }
+  TRY_VALUE(page, ds2476.readMemory(DS2476::romOptionsPage));
+  DS2476::RomOptions romOptions(page);
+  if (!romOptions.romBlockDisable()) {
+    romOptions.setRomBlockDisable(true);
+    TRY(ds2476.writeMemory(DS2476::romOptionsPage, page));
   }
-  return result;
-}
-
-error_code enableRomId(DS2476 & ds2476) {
-  DS2476::Page::array page;
-  error_code result = ds2476.readMemory(DS2476::romOptionsPage, page);
-  if (!result) {
-    DS2476::RomOptions romOptions(page);
-    if (!romOptions.romBlockDisable()) {
-      romOptions.setRomBlockDisable(true);
-      result = ds2476.writeMemory(DS2476::romOptionsPage, page);
-    }
-  }
-  return result;
+  return none;
 }
 
 static void setAnonymous(RomId::span romId) {