/// <summary>
        /// <P>Verifies user's authentication response.  User is "authenticated" if
        /// and only if the digital signature generated the user iButton matches
        /// the digital signature generated by the coprocessor after the user's
        /// unique secret has been recreated on the coprocessor.</P>
        ///
        /// <P><B>Flow of action: </B>
        ///   <ul>
        ///     <li> Generate 3-byte "challenge" on coprocessor </li>
        ///     <li> Write challenge to scratchpad of user </li>
        ///     <li> Read account data page with signature </li>
        ///     <li> Attempt to match user's signature with the coprocessor </li>
        ///   </ul></P>
        /// </summary>
        /// <param name="user"> SHAiButtonUser upon which the transaction occurs.
        /// </param>
        /// <seealso cref= SHAiButtonCopr#generateChallenge(int,byte[],int) </seealso>
        /// <seealso cref= SHAiButtonCopr#verifyAuthentication(byte[],byte[],byte[],byte[],byte) </seealso>
        /// <seealso cref= SHAiButtonUser#readAccountData(byte[],int,byte[],int,byte[],int) </seealso>
        /// <seealso cref= #getLastError() </seealso>
        public override bool verifyUser(SHAiButtonUser user)
        {
            lock (this)
            {
                //clear any error
                this.lastError = SHATransaction.NO_ERROR;

                //local vars
                byte[] fullBindCode = this.verifyUser_fullBindCode;
                byte[] scratchpad   = this.verifyUser_scratchpad;
                byte[] accountData  = this.verifyUser_accountData;
                byte[] mac          = this.verifyUser_mac;
                byte[] chlg         = this.verifyUser_chlg;

                int wcc;

                //Generate random challenge. This must be done on the
                //coprocessor, otherwise flags aren't setup for VALIDATE_PAGE.
                if (!copr.generateChallenge(0, chlg, 0))
                {
                    lastError = COPR_COMPUTE_CHALLENGE_FAILED;
                    return(false);
                }

                //have user answer the challenge
                wcc = user.readAccountData(chlg, 0, accountData, 0, mac, 0);

                if (wcc < 0)
                {
                    if (user.hasWriteCycleCounter())
                    {
                        // failed to read account data
                        this.lastError = SHATransaction.USER_READ_AUTH_FAILED;
                        return(false);
                    }
                    Array.Copy(ffBlock, 0, scratchpad, 8, 4);
                }
                else
                {
                    //copy the write cycle counter into scratchpad
                    Convert.toByteArray(wcc, scratchpad, 8, 4);
                }

                //get the user's fullBindCode, formatted for user device
                user.getFullBindCode(fullBindCode, 0);

                //get the user address and page num from fullBindCode
                Array.Copy(fullBindCode, 4, scratchpad, 12, 8);

                //set the same challenge bytes
                Array.Copy(chlg, 0, scratchpad, 20, 3);

                OneWireEventSource.Log.Debug("------------------------------------");
                OneWireEventSource.Log.Debug("Verifying user");
                OneWireEventSource.Log.Debug("chlg: " + Convert.toHexString(chlg));
                OneWireEventSource.Log.Debug("accountData: " + Convert.toHexString(accountData));
                OneWireEventSource.Log.Debug("mac: " + Convert.toHexString(mac));
                OneWireEventSource.Log.Debug("wcc: " + user.WriteCycleCounter);
                OneWireEventSource.Log.Debug("fullBindCode: " + Convert.toHexString(fullBindCode));
                OneWireEventSource.Log.Debug("scratchpad: " + Convert.toHexString(scratchpad));
                OneWireEventSource.Log.Debug("------------------------------------");

                if (!copr.verifyAuthentication(fullBindCode, accountData, scratchpad, mac, user.AuthorizationCommand))
                {
                    this.lastError = SHATransaction.COPROCESSOR_FAILURE;
                    return(false);
                }

                return(true);
            }
        }