Aleksandrs Gumenuks / MaximInterface_Extended

Dependents:   mbed_DS28EC20_GPIO

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS28C36_DS2476.cpp Source File

DS28C36_DS2476.cpp

00001 /*******************************************************************************
00002 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
00003 *
00004 * Permission is hereby granted, free of charge, to any person obtaining a
00005 * copy of this software and associated documentation files (the "Software"),
00006 * to deal in the Software without restriction, including without limitation
00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008 * and/or sell copies of the Software, and to permit persons to whom the
00009 * Software is furnished to do so, subject to the following conditions:
00010 *
00011 * The above copyright notice and this permission notice shall be included
00012 * in all copies or substantial portions of the Software.
00013 *
00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020 * OTHER DEALINGS IN THE SOFTWARE.
00021 *
00022 * Except as contained in this notice, the name of Maxim Integrated
00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024 * Products, Inc. Branding Policy.
00025 *
00026 * The mere transfer of this software does not imply any licenses
00027 * of trade secrets, proprietary technology, copyrights, patents,
00028 * trademarks, maskwork rights, or any other form of intellectual
00029 * property whatsoever. Maxim Integrated Products, Inc. retains all
00030 * ownership rights.
00031 *******************************************************************************/
00032 
00033 #include <algorithm>
00034 #include <MaximInterface/Links/I2CMaster.hpp>
00035 #include <MaximInterface/Utilities/Error.hpp>
00036 #include <MaximInterface/Utilities/RomId.hpp>
00037 #include "DS28C36_DS2476.hpp"
00038 
00039 namespace MaximInterface {
00040 
00041 using namespace Ecc256;
00042 using std::copy;
00043 
00044 static error_code convertResultByte(uint_least8_t resultByte) {
00045   error_code errorCode;
00046   if (resultByte != 0xAA) {
00047     errorCode.assign((resultByte == 0x00)
00048                          ? static_cast<int>(DS28C36::AuthenticationError)
00049                          : resultByte,
00050                      DS28C36::errorCategory());
00051   }
00052   return errorCode;
00053 }
00054 
00055 const int DS28C36::publicKeyAxPage;
00056 const int DS28C36::publicKeyAyPage;
00057 const int DS28C36::publicKeyBxPage;
00058 const int DS28C36::publicKeyByPage;
00059 const int DS28C36::publicKeyCxPage;
00060 const int DS28C36::publicKeyCyPage;
00061 const int DS28C36::privateKeyAPage;
00062 const int DS28C36::privateKeyBPage;
00063 const int DS28C36::privateKeyCPage;
00064 const int DS28C36::secretAPage;
00065 const int DS28C36::secretBPage;
00066 const int DS28C36::decrementCounterPage;
00067 const int DS28C36::romOptionsPage;
00068 const int DS28C36::gpioControlPage;
00069 const int DS28C36::publicKeySxPage;
00070 const int DS28C36::publicKeySyPage;
00071 const int DS28C36::memoryPages;
00072 
00073 error_code DS28C36::writeMemory(int pageNum, Page::const_span page) {
00074   if (pageNum < 0 || pageNum >= memoryPages) {
00075     return make_error_code(InvalidParameterError);
00076   }
00077 
00078   uint_least8_t buffer[1 + Page::size];
00079   buffer[0] = pageNum;
00080   copy(page.begin(), page.end(), buffer + 1);
00081   error_code result = writeCommand(0x96, buffer);
00082   if (!result) {
00083     sleep(writeMemoryTimeMs);
00084     result = readFixedLengthResponse(make_span(buffer, 1));
00085     if (!result) {
00086       result = convertResultByte(buffer[0]);
00087     }
00088   }
00089   return result;
00090 }
00091 
00092 error_code DS28C36::readMemory(int pageNum, Page::span page) {
00093   if (pageNum < 0 || pageNum >= memoryPages) {
00094     return make_error_code(InvalidParameterError);
00095   }
00096 
00097   const uint_least8_t parameter = pageNum;
00098   error_code result = writeCommand(0x69, make_span(&parameter, 1));
00099   if (!result) {
00100     sleep(readMemoryTimeMs);
00101     array<uint_least8_t, 1 + Page::size> response;
00102     result = readFixedLengthResponse(response);
00103     if (!result) {
00104       result = convertResultByte(response[0]);
00105       copy(response.begin() + 1, response.end(), page.begin());
00106     }
00107   }
00108   return result;
00109 }
00110 
00111 error_code DS28C36::writeBuffer(span<const uint_least8_t> data) {
00112   return writeCommand(0x87, data);
00113 }
00114 
00115 error_code DS28C36::readBuffer(std::vector<uint_least8_t> & data) {
00116   error_code result = writeCommand(0x5A);
00117   if (!result) {
00118     data.resize(80);
00119     span<uint_least8_t> dataSpan(data);
00120     result = readVariableLengthResponse(dataSpan);
00121     if (result) {
00122       data.clear();
00123     } else {
00124       data.resize(dataSpan.size());
00125     }
00126   }
00127   return result;
00128 }
00129 
00130 error_code DS28C36::readPageProtection(int pageNum,
00131                                        PageProtection & protection) {
00132   if (pageNum < 0 || pageNum >= memoryPages) {
00133     return make_error_code(InvalidParameterError);
00134   }
00135 
00136   uint_least8_t buffer = pageNum;
00137   error_code result = writeCommand(0xAA, make_span(&buffer, 1));
00138   if (!result) {
00139     sleep(readMemoryTimeMs);
00140     result = readFixedLengthResponse(make_span(&buffer, 1));
00141     if (!result) {
00142       protection = buffer;
00143     }
00144   }
00145   return result;
00146 }
00147 
00148 error_code DS28C36::setPageProtection(int pageNum,
00149                                       const PageProtection & protection) {
00150   if (pageNum < 0 || pageNum >= memoryPages) {
00151     return make_error_code(InvalidParameterError);
00152   }
00153 
00154   uint_least8_t buffer[] = {static_cast<uint_least8_t>(pageNum),
00155                             static_cast<uint_least8_t>(protection.to_ulong())};
00156   error_code result = writeCommand(0xC3, buffer);
00157   if (!result) {
00158     sleep(writeMemoryTimeMs);
00159     result = readFixedLengthResponse(make_span(buffer, 1));
00160     if (!result) {
00161       result = convertResultByte(buffer[0]);
00162     }
00163   }
00164   return result;
00165 }
00166 
00167 error_code DS28C36::decrementCounter() {
00168   error_code result = writeCommand(0xC9);
00169   if (!result) {
00170     sleep(writeMemoryTimeMs);
00171     uint_least8_t response;
00172     result = readFixedLengthResponse(make_span(&response, 1));
00173     if (!result) {
00174       result = convertResultByte(response);
00175     }
00176   }
00177   return result;
00178 }
00179 
00180 error_code DS28C36::readRng(span<uint_least8_t> data) {
00181   if ((data.size() < 1) || (data.size() > 64)) {
00182     return make_error_code(InvalidParameterError);
00183   }
00184 
00185   data[0] = static_cast<uint_least8_t>(data.size() - 1);
00186   error_code result = writeCommand(0xD2, data.first(1));
00187   if (!result) {
00188     sleep(sha256ComputationTimeMs);
00189     result = readFixedLengthResponse(data);
00190   }
00191   return result;
00192 }
00193 
00194 error_code DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum,
00195                                         EncryptionChallenge::span challenge,
00196                                         Page::span data) {
00197   if (pageNum < 0 || pageNum >= memoryPages) {
00198     return make_error_code(InvalidParameterError);
00199   }
00200 
00201   const uint_least8_t parameter = (secretNum << 6) | pageNum;
00202   error_code result = writeCommand(0x4B, make_span(&parameter, 1));
00203   if (!result) {
00204     sleep(readMemoryTimeMs + sha256ComputationTimeMs);
00205     uint_least8_t response[1 + EncryptionChallenge::size + Page::size];
00206     result = readFixedLengthResponse(response);
00207     if (!result) {
00208       result = convertResultByte(response[0]);
00209       const uint_least8_t * begin = response + 1;
00210       const uint_least8_t * end = begin + challenge.size();
00211       copy(begin, end, challenge.begin());
00212       begin = end;
00213       end = begin + data.size();
00214       copy(begin, end, data.begin());
00215     }
00216   }
00217   return result;
00218 }
00219 
00220 error_code DS28C36::computeAndReadPageAuthentication(int pageNum,
00221                                                      AuthType authType) {
00222   if (pageNum < 0 || pageNum >= memoryPages) {
00223     return make_error_code(InvalidParameterError);
00224   }
00225 
00226   const uint_least8_t parameter = (authType << 5) | pageNum;
00227   return writeCommand(0xA5, make_span(&parameter, 1));
00228 }
00229 
00230 error_code
00231 DS28C36::computeAndReadPageAuthentication(int pageNum, KeyNum keyNum,
00232                                           Signature::span signature) {
00233   AuthType authType;
00234   switch (keyNum) {
00235   case KeyNumA:
00236     authType = EcdsaWithKeyA;
00237     break;
00238   case KeyNumB:
00239     authType = EcdsaWithKeyB;
00240     break;
00241   case KeyNumC:
00242     authType = EcdsaWithKeyC;
00243     break;
00244   default:
00245     return make_error_code(InvalidParameterError);
00246   }
00247   error_code result = computeAndReadPageAuthentication(pageNum, authType);
00248   if (!result) {
00249     sleep(readMemoryTimeMs + generateEcdsaSignatureTimeMs);
00250     uint_least8_t response[1 + 2 * Scalar::size];
00251     result = readFixedLengthResponse(response);
00252     if (!result) {
00253       result = convertResultByte(response[0]);
00254       const uint_least8_t * begin = response + 1;
00255       const uint_least8_t * end = begin + signature.s.size();
00256       copy(begin, end, signature.s.begin());
00257       begin = end;
00258       end = begin + signature.r.size();
00259       copy(begin, end, signature.r.begin());
00260     }
00261   }
00262   return result;
00263 }
00264 
00265 error_code DS28C36::computeAndReadPageAuthentication(int pageNum,
00266                                                      SecretNum secretNum,
00267                                                      Sha256::Hash::span hmac) {
00268   AuthType authType;
00269   switch (secretNum) {
00270   case SecretNumA:
00271     authType = HmacWithSecretA;
00272     break;
00273   case SecretNumB:
00274     authType = HmacWithSecretB;
00275     break;
00276   case SecretNumS:
00277     authType = HmacWithSecretS;
00278     break;
00279   default:
00280     return make_error_code(InvalidParameterError);
00281   }
00282   error_code result = computeAndReadPageAuthentication(pageNum, authType);
00283   if (!result) {
00284     sleep(readMemoryTimeMs + sha256ComputationTimeMs);
00285     array<uint_least8_t, 1 + Sha256::Hash::size> response;
00286     result = readFixedLengthResponse(response);
00287     if (!result) {
00288       result = convertResultByte(response[0]);
00289       copy(response.begin() + 1, response.end(), hmac.begin());
00290     }
00291   }
00292   return result;
00293 }
00294 
00295 error_code DS28C36::authenticatedSha2WriteMemory(int pageNum,
00296                                                  SecretNum secretNum,
00297                                                  Page::const_span page) {
00298   if (pageNum < 0 || pageNum >= memoryPages) {
00299     return make_error_code(InvalidParameterError);
00300   }
00301 
00302   uint_least8_t buffer[1 + Page::size];
00303   buffer[0] = (secretNum << 6) | pageNum;
00304   copy(page.begin(), page.end(), buffer + 1);
00305   error_code result = writeCommand(0x99, buffer);
00306   if (!result) {
00307     sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs));
00308     result = readFixedLengthResponse(make_span(buffer, 1));
00309     if (!result) {
00310       result = convertResultByte(buffer[0]);
00311     }
00312   }
00313   return result;
00314 }
00315 
00316 error_code DS28C36::computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
00317                                              SecretNum dsecretNum,
00318                                              bool writeProtectEnable) {
00319   // User pages only
00320   if (pageNum < 0 || pageNum > 15) {
00321     return make_error_code(InvalidParameterError);
00322   }
00323 
00324   uint_least8_t buffer[] = {
00325       static_cast<uint_least8_t>((dsecretNum << 6) | (msecretNum << 4) |
00326                                  pageNum),
00327       static_cast<uint_least8_t>(writeProtectEnable ? 0x80 : 0x00)};
00328   error_code result = writeCommand(0x3C, buffer);
00329   if (!result) {
00330     sleep(sha256ComputationTimeMs +
00331           ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs));
00332     result = readFixedLengthResponse(make_span(buffer, 1));
00333     if (!result) {
00334       result = convertResultByte(buffer[0]);
00335     }
00336   }
00337   return result;
00338 }
00339 
00340 error_code DS28C36::generateEcc256KeyPair(KeyNum keyNum,
00341                                           bool writeProtectEnable) {
00342   if (keyNum == KeyNumS) {
00343     return make_error_code(InvalidParameterError);
00344   }
00345 
00346   uint_least8_t buffer = keyNum;
00347   if (writeProtectEnable) {
00348     buffer |= 0x80;
00349   }
00350   error_code result = writeCommand(0xCB, make_span(&buffer, 1));
00351   if (!result) {
00352     sleep(generateEccKeyPairTimeMs);
00353     result = readFixedLengthResponse(make_span(&buffer, 1));
00354     if (!result) {
00355       result = convertResultByte(buffer);
00356     }
00357   }
00358   return result;
00359 }
00360 
00361 error_code DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock,
00362                                           span<const uint_least8_t> data) {
00363   const span<const uint_least8_t>::index_type maxDataSize = 64;
00364 
00365   if (data.size() < 1 || data.size() > maxDataSize) {
00366     return make_error_code(InvalidParameterError);
00367   }
00368 
00369   uint_least8_t buffer[1 + maxDataSize];
00370   buffer[0] = 0;
00371   if (firstBlock) {
00372     buffer[0] |= 0x40;
00373   }
00374   if (lastBlock) {
00375     buffer[0] |= 0x80;
00376   }
00377   copy(data.begin(), data.end(), buffer + 1);
00378   error_code result = writeCommand(0x33, make_span(buffer, data.size() + 1));
00379   if (!result) {
00380     sleep(sha256ComputationTimeMs);
00381     result = readFixedLengthResponse(make_span(buffer, 1));
00382     if (!result) {
00383       result = convertResultByte(buffer[0]);
00384     }
00385   }
00386   return result;
00387 }
00388 
00389 error_code DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
00390                                          Signature::const_span signature,
00391                                          PioState pioa, PioState piob) {
00392   uint_least8_t buffer[1 + 2 * Scalar::size];
00393   buffer[0] = keyNum | (hashType << 2);
00394   if (pioa != Unchanged) {
00395     buffer[0] |= 0x20;
00396   }
00397   if (pioa == Conducting) {
00398     buffer[0] |= 0x10;
00399   }
00400   if (piob != Unchanged) {
00401     buffer[0] |= 0x80;
00402   }
00403   if (piob == Conducting) {
00404     buffer[0] |= 0x40;
00405   }
00406   uint_least8_t * bufferIt =
00407       copy(signature.r.begin(), signature.r.end(), buffer + 1);
00408   copy(signature.s.begin(), signature.s.end(), bufferIt);
00409   error_code result = writeCommand(0x59, buffer);
00410   if (!result) {
00411     sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs +
00412           ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0));
00413     result = readFixedLengthResponse(make_span(buffer, 1));
00414     if (!result) {
00415       result = convertResultByte(buffer[0]);
00416     }
00417   }
00418   return result;
00419 }
00420 
00421 error_code
00422 DS28C36::authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum,
00423                                     int csOffset,
00424                                     Signature::const_span signature) {
00425   if (((keyNum != KeyNumA) && (keyNum != KeyNumB)) || (csOffset < 0) ||
00426       (csOffset > 31)) {
00427     return make_error_code(InvalidParameterError);
00428   }
00429 
00430   uint_least8_t buffer[1 + 2 * Scalar::size];
00431   buffer[0] = (csOffset << 3) | (keyNum << 2);
00432   if (ecdh) {
00433     buffer[0] |= 0x02;
00434   }
00435   if (authWrites) {
00436     buffer[0] |= 0x01;
00437   }
00438   uint_least8_t * bufferIt =
00439       copy(signature.r.begin(), signature.r.end(), buffer + 1);
00440   copy(signature.s.begin(), signature.s.end(), bufferIt);
00441   error_code result = writeCommand(0xA8, buffer);
00442   if (!result) {
00443     sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs);
00444     result = readFixedLengthResponse(make_span(buffer, 1));
00445     if (!result) {
00446       result = convertResultByte(buffer[0]);
00447     }
00448   }
00449   return result;
00450 }
00451 
00452 error_code DS28C36::authenticatedEcdsaWriteMemory(int pageNum,
00453                                                   Page::const_span page) {
00454   if (pageNum < 0 || pageNum >= memoryPages) {
00455     return make_error_code(InvalidParameterError);
00456   }
00457 
00458   uint_least8_t buffer[1 + Page::size];
00459   buffer[0] = pageNum;
00460   copy(page.begin(), page.end(), buffer + 1);
00461   error_code result = writeCommand(0x89, buffer);
00462   if (!result) {
00463     sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs +
00464           sha256ComputationTimeMs);
00465     result = readFixedLengthResponse(make_span(buffer, 1));
00466     if (!result) {
00467       result = convertResultByte(buffer[0]);
00468     }
00469   }
00470   return result;
00471 }
00472 
00473 error_code DS28C36::writeCommand(uint_least8_t command,
00474                                  span<const uint_least8_t> parameters) {
00475   error_code result = master->start(address_);
00476   if (result) {
00477     master->stop();
00478     return result;
00479   }
00480   result = master->writeByte(command);
00481   if (result) {
00482     master->stop();
00483     return result;
00484   }
00485   if (!parameters.empty()) {
00486     result = master->writeByte(static_cast<uint_least8_t>(parameters.size()));
00487     if (result) {
00488       master->stop();
00489       return result;
00490     }
00491     result = master->writeBlock(parameters);
00492     if (result) {
00493       master->stop();
00494       return result;
00495     }
00496   }
00497   result = master->stop();
00498   return result;
00499 }
00500 
00501 error_code DS28C36::readVariableLengthResponse(span<uint_least8_t> & response) {
00502   error_code result = master->start(address_ | 1);
00503   if (result) {
00504     master->stop();
00505     return result;
00506   }
00507   uint_least8_t length;
00508   result = master->readByte(I2CMaster::Ack, length);
00509   if (result) {
00510     master->stop();
00511     return result;
00512   }
00513   if (length > response.size()) {
00514     master->stop();
00515     return make_error_code(InvalidResponseError);
00516   }
00517   response = response.first(length);
00518   if (!response.empty()) {
00519     result = master->readBlock(I2CMaster::Nack, response);
00520     if (result) {
00521       master->stop();
00522       return result;
00523     }
00524   }
00525   result = master->stop();
00526   return result;
00527 }
00528 
00529 error_code DS28C36::readFixedLengthResponse(span<uint_least8_t> response) {
00530   const span<uint_least8_t>::index_type requestedResponseSize = response.size();
00531   error_code result = readVariableLengthResponse(response);
00532   if (!result && response.size() != requestedResponseSize) {
00533     result = make_error_code(InvalidResponseError);
00534   }
00535   return result;
00536 }
00537 
00538 const error_category & DS28C36::errorCategory() {
00539   static class : public error_category {
00540   public:
00541     virtual const char * name() const { return "DS28C36"; }
00542 
00543     virtual std::string message(int condition) const {
00544       switch (condition) {
00545       case ProtectionError:
00546         return "Protection Error";
00547 
00548       case InvalidParameterError:
00549         return "Invalid Parameter Error";
00550 
00551       case InvalidSequenceError:
00552         return "Invalid Sequence Error";
00553 
00554       case InvalidEcdsaInputOrResultError:
00555         return "Invalid ECDSA Input or Result Error";
00556 
00557       case AuthenticationError:
00558         return "Authentication Error";
00559 
00560       case InvalidResponseError:
00561         return "Invalid Response Error";
00562 
00563       default:
00564         return defaultErrorMessage(condition);
00565       }
00566     }
00567   } instance;
00568   return instance;
00569 }
00570 
00571 error_code DS2476::generateEcdsaSignature(KeyNum keyNum,
00572                                           Signature::span signature) {
00573   if (keyNum == KeyNumS) {
00574     return make_error_code(InvalidParameterError);
00575   }
00576 
00577   const uint_least8_t parameter = keyNum;
00578   error_code result = writeCommand(0x1E, make_span(&parameter, 1));
00579   if (!result) {
00580     sleep(generateEcdsaSignatureTimeMs);
00581     uint_least8_t response[1 + 2 * Scalar::size];
00582     result = readFixedLengthResponse(response);
00583     if (!result) {
00584       result = convertResultByte(response[0]);
00585       const uint_least8_t * begin = response + 1;
00586       const uint_least8_t * end = begin + signature.s.size();
00587       copy(begin, end, signature.s.begin());
00588       begin = end;
00589       end = begin + signature.r.size();
00590       copy(begin, end, signature.r.begin());
00591     }
00592   }
00593   return result;
00594 }
00595 
00596 error_code DS2476::computeSha2UniqueSecret(SecretNum msecretNum) {
00597   uint_least8_t buffer = msecretNum << 4;
00598   error_code result = writeCommand(0x55, make_span(&buffer, 1));
00599   if (!result) {
00600     sleep(sha256ComputationTimeMs);
00601     result = readFixedLengthResponse(make_span(&buffer, 1));
00602     if (!result) {
00603       convertResultByte(buffer);
00604     }
00605   }
00606   return result;
00607 }
00608 
00609 error_code DS2476::computeSha2Hmac(Sha256::Hash::span hmac) {
00610   error_code result = writeCommand(0x2D);
00611   if (!result) {
00612     sleep(sha256ComputationTimeMs);
00613     array<uint_least8_t, 1 + Sha256::Hash::size> response;
00614     result = readFixedLengthResponse(response);
00615     if (!result) {
00616       result = convertResultByte(response[0]);
00617       copy(response.begin() + 1, response.end(), hmac.begin());
00618     }
00619   }
00620   return result;
00621 }
00622 
00623 error_code computeMultiblockHash(DS28C36 & ds28c36,
00624                                  span<const uint_least8_t> data) {
00625   error_code result;
00626   span<const uint_least8_t>::index_type dataIdx = 0;
00627   while (dataIdx < data.size() && !result) {
00628     const span<const uint_least8_t>::index_type remainingSize =
00629         data.size() - dataIdx;
00630     const span<const uint_least8_t>::index_type chunkSize =
00631         std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
00632     result =
00633         ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
00634                                       data.subspan(dataIdx, chunkSize));
00635     dataIdx += chunkSize;
00636   }
00637   return result;
00638 }
00639 
00640 error_code verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
00641                                 span<const uint_least8_t> data,
00642                                 Signature::const_span signature,
00643                                 DS28C36::PioState pioa,
00644                                 DS28C36::PioState piob) {
00645   error_code result = computeMultiblockHash(ds28c36, data);
00646   if (!result) {
00647     result = ds28c36.verifyEcdsaSignature(publicKey, DS28C36::THASH, signature,
00648                                           pioa, piob);
00649   }
00650   return result;
00651 }
00652 
00653 error_code verifyEcdsaSignature(DS28C36 & ds28c36,
00654                                 PublicKey::const_span publicKey,
00655                                 span<const uint_least8_t> data,
00656                                 Signature::const_span signature,
00657                                 DS28C36::PioState pioa,
00658                                 DS28C36::PioState piob) {
00659   error_code result =
00660       ds28c36.writeMemory(DS28C36::publicKeySxPage, publicKey.x);
00661   if (!result) {
00662     result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y);
00663   }
00664   if (!result) {
00665     result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, signature,
00666                                   pioa, piob);
00667   }
00668   return result;
00669 }
00670 
00671 error_code readRomIdAndManId(DS28C36 & ds28c36, RomId::span romId,
00672                              ManId::span manId) {
00673   DS28C36::Page::array page;
00674   error_code result = ds28c36.readMemory(DS28C36::romOptionsPage, page);
00675   if (!result) {
00676     const DS28C36::RomOptions romOptions(page);
00677     copy(romOptions.romId(), romId);
00678     copy(romOptions.manId(), manId);
00679   }
00680   return result;
00681 }
00682 
00683 error_code enableCoprocessor(DS2476 & ds2476) {
00684   DS2476::Page::array page;
00685   error_code result = ds2476.readMemory(DS2476::gpioControlPage, page);
00686   if (!result) {
00687     DS2476::GpioControl gpioControl(page);
00688     if (!gpioControl.pioaConducting()) {
00689       gpioControl.setPioaConducting(true);
00690       result = ds2476.writeMemory(DS2476::gpioControlPage, page);
00691     }
00692   }
00693   return result;
00694 }
00695 
00696 error_code enableRomId(DS2476 & ds2476) {
00697   DS2476::Page::array page;
00698   error_code result = ds2476.readMemory(DS2476::romOptionsPage, page);
00699   if (!result) {
00700     DS2476::RomOptions romOptions(page);
00701     if (!romOptions.romBlockDisable()) {
00702       romOptions.setRomBlockDisable(true);
00703       result = ds2476.writeMemory(DS2476::romOptionsPage, page);
00704     }
00705   }
00706   return result;
00707 }
00708 
00709 static void setAnonymous(RomId::span romId) {
00710   std::fill(romId.begin(), romId.end(), 0xFF);
00711 }
00712 
00713 DS28C36::PageAuthenticationData &
00714 DS28C36::PageAuthenticationData::setAnonymousRomId() {
00715   setAnonymous(romId());
00716   return *this;
00717 }
00718 
00719 DS28C36::EncryptionHmacData & DS28C36::EncryptionHmacData::setAnonymousRomId() {
00720   setAnonymous(romId());
00721   return *this;
00722 }
00723 
00724 } // namespace MaximInterface