0

Solidity Code

I am trying to sign a message and verify it later. But while verifying, the returned address from the ecrecover is very odd and not matching with any of the accounts I am using. Not sure what am I missing here!!!

Could someone please help me?

 pragma solidity >=0.7.0 <0.9.0;
// signs data from a specific account. This account needs to be unlocked.
 
library CryptoSuite {
    function splitSignature(bytes memory sig) internal pure returns(uint8 v, bytes32 r, bytes32 s) {
        require(sig.length == 65);
 
        assembly{
            // first 32bytes
            r := mload(add(sig, 32))
 
            // next 32bytes
            s := mload(add(sig, 64))
 
            // last 32bytes
            v := byte(0, mload(add(sig,96)))
        }
        return (v, r, s);
    }
    function recoverSigner(bytes32 message, bytes memory sig) internal pure returns (address) {
        (uint8 v, bytes32 r, bytes32 s) = splitSignature(sig);
        return ecrecover(message, v, r, s);   //recovers the value of the person who signed this
    }
}
 
contract ColdChain{
    enum Mode { ISSUER, PROVER, VERIFIER }
    struct Entity {
        address id;
        Mode mode;                  // Passing the enum Mode here.
        uint[] certificateIds;      // to track all the certificates that this entity is involved in
    }
 
    enum Status { MANUFACTURED, DELIVERING_INTERNATIONAL, STORED, DELIVERING_LOCAL, DELIVERED }   // represents some constant
    struct Certificate {
        uint id;
        Entity issuer;             // someone should issue the certificate
        Entity prover;             // someone must prove this certificate is not false
        bytes signature;           // this signature will be passed to inbuilt recoverSigner to check the status.
        Status status;             // passing the enum Status here
    }
 
   struct VaccineBatch {
       uint id;           
       string brand;
       address manufacturer;
       uint[] certificateIds;
   }
 
   uint public constant MAX_CERTIFICATIONS = 2;    //certificate can't be verified more than the max. Here it is 2.
 
   uint[] public certificateIds;      // to keep track of all the certificate ids.
   uint[] public vaccineBatchIds;     // to track all the vaccine batchids
 
   mapping(uint => VaccineBatch) public vaccineBatches;  // creating mapping (key value pair) for each of the structs.
   mapping(uint => Certificate) public certificates;
   mapping(address => Entity) public entities;
 
   event AddEntity(address entityId, string entityMode);                      //pushes data from smart contracts to consumers like front end, mobile app using emit followed by it.
   event AddVaccineBatch(uint vaccineBatchId, address indexed manufacturer);  //Indexed is to filter based on manufacturer.
                                                                                                // maximum of 3 index can be used in events.
                                                                                                // emitted values can't be stored in smart contracts.
   event IssueCertificate(address indexed issuer, address indexed prover, uint certificateId);
 
  function addEntity(address _id, string memory _mode) public {
       Mode mode = unmarshalMode(_mode);                                      //mode is a string and it needs to converted to enum which unmarshall (golang) does.
       uint[] memory _certificateIds = new uint[](MAX_CERTIFICATIONS);
       Entity memory entity = Entity(_id, mode, _certificateIds);
       entities[_id] = entity;
       emit AddEntity(entity.id, _mode);
   }
 
   function unmarshalMode(string memory _mode) private pure returns(Mode mode) {
       bytes32 encodedMode  = keccak256(abi.encodePacked(_mode));
       bytes32 encodedMode0 = keccak256(abi.encodePacked("ISSUER"));
       bytes32 encodedMode1 = keccak256(abi.encodePacked("PROVER"));
       bytes32 encodedMode2 = keccak256(abi.encodePacked("VERIFIER"));
 
       if(encodedMode == encodedMode0) {
           return Mode.ISSUER;
       }
       else if(encodedMode == encodedMode1) {
           return Mode.PROVER;
       }
       else if(encodedMode == encodedMode2) {
           return Mode.VERIFIER;
       }
       revert("received invalid entity mode");
   }
 
   function addVaccineBatch(string memory brand, address manufacturer) public returns(uint) {
       uint[] memory _certificateIds = new uint[](MAX_CERTIFICATIONS);
       uint id = vaccineBatchIds.length;
       VaccineBatch memory batch = VaccineBatch(id, brand, manufacturer, _certificateIds);
 
       vaccineBatches[id] = batch;
       vaccineBatchIds.push(id);
 
       emit AddVaccineBatch(batch.id, batch.manufacturer);
       return id;
   }
 
   function issueCertificate(
       address _issuer, address _prover, string memory _status, uint vaccineBatchId, bytes memory signature) public returns(uint) {
              Entity memory issuer = entities[_issuer];
              require(issuer.mode == Mode.ISSUER);
 
              Entity memory prover = entities[_prover];
              require(prover.mode == Mode.PROVER);
             
              Status status = unmarshalStatus(_status);
              uint id = certificateIds.length;
             
              Certificate memory certificate = Certificate(id, issuer, prover, signature, status);
              certificateIds.push(certificateIds.length);
              certificates[certificateIds.length-1] = certificate;
             
              emit IssueCertificate(_issuer, _prover, certificateIds.length-1);
              return certificateIds.length-1;
    }  
    
   function unmarshalStatus(string memory _status) private pure returns(Status status) {
       bytes32 encodedStatus = keccak256(abi.encodePacked(_status));
       bytes32 encodedStatus0 = keccak256(abi.encodePacked("MANUFACTURED"));
       bytes32 encodedStatus1 = keccak256(abi.encodePacked("DELIVERING_INTERNATIONAL"));
       bytes32 encodedStatus2 = keccak256(abi.encodePacked("STORED"));
       bytes32 encodedStatus3 = keccak256(abi.encodePacked("DELIVERING_LOCAL"));
       bytes32 encodedStatus4 = keccak256(abi.encodePacked("DELIVERED"));
 
       if(encodedStatus == encodedStatus0) {
           return Status.MANUFACTURED;
       }
       else if(encodedStatus == encodedStatus1) {
           return Status.DELIVERING_INTERNATIONAL;
       }
       else if(encodedStatus == encodedStatus2) {
           return Status.STORED;
       }
       else if(encodedStatus == encodedStatus3) {
           return Status.DELIVERING_LOCAL;
       }
       else if(encodedStatus == encodedStatus4) {
           return Status.DELIVERED;
       }
       revert("received invalid certification status");
   }  
 
   function isMatchingSignature(bytes32 message, uint id, address issuer) public view returns (bytes32) {
       Certificate memory cert = certificates[id];
       require(cert.issuer.id == issuer);
 
       address recoveredSigner = CryptoSuite.recoverSigner(message, cert.signature);
       //return (message);
       return recoveredSigner == cert.issuer.id;
   }
 
}

Java Script Code is returning false with incorrect address

    const { expectEvent , BN } = require("@openzeppelin/test-helpers");
const HDWalletprovider = require("@truffle/hdwallet-provider");
const Web3 = require("web3");
 
const ColdChain = artifacts.require("ColdChain");
contract ('ColdChain', (accounts) => {
 
  before(async() => {
    this.owner = accounts[0];           //adding the accounts[0] which we got while deploying the conntract. Please check log for account[0]
 
    this.VACCINE_BRANDS ={
      Pfizer: "Pfizer-BioNTech",
      Moderna: "Moderna",
      Janssen : "Jhonson & Jhonson's Janssen",
      Sputnik : "Sputnik V"
    };
 
    //enums
    this.ModeEnums  ={
      ISSUER: {val : "ISSUER", pos:0},
      PROVER: {val : "PROVER", pos:1},
      VERIFIER: {val : "VERIFIER", pos:2},
    }
 
    this.StatusEnums ={ // { MANUFACTURED, DELIVERING_INTERNATIONAL, STORED, DELIVERING_LOCAL, DELIVERED }
      manufactured: {val : "MANUFACTURED", pos:0},
      delivering_international: {val : "DELIVERING_INTERNATIONAL", pos:1},
      stored: {val : "STORED", pos:2},
      delivering2: {val : "DELIVERING_LOCAL", pos:3},
      delivered: {val : "DELIVERED", pos:4}
    }
 
    this.defaultEntities = {
      manufacturerA : {id : accounts[1], mode:this.ModeEnums.PROVER.val},
      manufacturerB : {id : accounts[2], mode:this.ModeEnums.PROVER.val},
      inspector : {id : accounts[3], mode:this.ModeEnums.ISSUER.val},
      distributorGlobal : {id : accounts[4], mode:this.ModeEnums.VERIFIER.val},
      distributorLocal : {id : accounts[5], mode:this.ModeEnums.VERIFIER.val},
      immunizer : {id : accounts[6], mode:this.ModeEnums.ISSUER.val},
      traveller : {id : accounts[7], mode:this.ModeEnums.PROVER.val},
      borderAgent : {id : accounts[8], mode:this.ModeEnums.VERIFIER.val}
    };
 
    this.defaultVaccineBatches ={
      0: {brand: this.VACCINE_BRANDS.Pfizer, manufacturer:this.defaultEntities.manufacturerA.id},
      1: {brand: this.VACCINE_BRANDS.Moderna, manufacturer:this.defaultEntities.manufacturerA.id},
      2: {brand: this.VACCINE_BRANDS.Janssen, manufacturer:this.defaultEntities.manufacturerB.id},
      3: {brand: this.VACCINE_BRANDS.Sputnik, manufacturer:this.defaultEntities.manufacturerB.id},
      4: {brand: this.VACCINE_BRANDS.Pfizer, manufacturer:this.defaultEntities.manufacturerB.id},
      5: {brand: this.VACCINE_BRANDS.Pfizer, manufacturer:this.defaultEntities.manufacturerA.id},
      6: {brand: this.VACCINE_BRANDS.Moderna, manufacturer:this.defaultEntities.manufacturerA.id},
      7: {brand: this.VACCINE_BRANDS.Moderna, manufacturer:this.defaultEntities.manufacturerB.id},
      8: {brand: this.VACCINE_BRANDS.Sputnik, manufacturer:this.defaultEntities.manufacturerB.id},
      9: {brand: this.VACCINE_BRANDS.Janssen, manufacturer:this.defaultEntities.manufacturerA.id}
    };
 
    this.coldChainInstance = await ColdChain.deployed();
    this.providerOrUrl= "http://localhost:7545";
  });
 
 
  it('should add entities successfully', async () => {
    for(const entity in this.defaultEntities) {
      const { id, mode } = this.defaultEntities[entity];
 
      const result = await this.coldChainInstance.addEntity(    //adding the defined entities to the blockchain. In reutnr we will get the txn hash from BC
        id,
        mode,
        { from: this.owner }
      );
 
      console.log(result);
      expectEvent(result.receipt, "AddEntity", {
        entityId: id,
        entityMode: mode
      });
     
      // to add entities into the smart contracts in blockchain
      const retrievedEntity = await this.coldChainInstance.entities.call(id); // to check if the addded enties are there in block chain. throws exception if mismatches. Test it.
      assert.equal(id, retrievedEntity.id, "mismatch id");
      assert.equal(this.ModeEnums[mode].pos, retrievedEntity.mode.toString(), "mismatched modes");
    }
  });
 
  it('should add vaccine batches successfully', async () => {
    for(let i=0 ; i < Object.keys(this.defaultVaccineBatches).length; i++) {
      const { brand, manufacturer } = this.defaultVaccineBatches[i];
 
      const result = await this.coldChainInstance.addVaccineBatch(
        brand,
        manufacturer,
        { from: this.owner }
      );
 
      //console.log(result);
      expectEvent(result.receipt, "AddVaccineBatch", {
        vaccineBatchId: String(i),
        manufacturer: manufacturer
      });
     
      // to add entities into the smart contracts in blockchain
      const retrievedVaccineBatch= await this.coldChainInstance.vaccineBatches.call(i);
 
      // verify the entities added in the blockchain. read from BC and verify against a value.
      assert.equal(i, retrievedVaccineBatch.id);
      assert.equal(brand, retrievedVaccineBatch.brand);
      assert.equal(manufacturer, retrievedVaccineBatch.manufacturer);
      assert.equal(undefined, retrievedVaccineBatch.certificateIds);
      //17 transactions executed so far
 
    }
  });
 
  // Inspector signs the certification using the menoomic (should match with the mnemonic used while launching the ganache) and url using web3.eth.sign
  it('should sign a message and store the certificate from the issuer to the prover', async () => {
    const mnemonic = "gift session kitchen bulk sponsor catalog pluck actor wide artist job collect";
    const providerOrUrl = "http://localhost:7545"
    const provider =new HDWalletprovider({
      mnemonic,
      providerOrUrl
    });
    this.web3 = new Web3(provider);
 
    const {inspector, manufacturerA} = this.defaultEntities;
    const vaccineBatchId = 0;
    const message = `Inspector(${inspector.id}) has certified vaccine batch #${vaccineBatchId} for Manufacturer (${manufacturerA.id}).`;
    const signature = await this.web3.eth.sign(this.web3.utils.keccak256(message), inspector.id);
  
    // send this signature the smart contract or BC
    const result = await this.coldChainInstance.issueCertificate(
      inspector.id,
      manufacturerA.id,
      this.StatusEnums.manufactured.val,
      vaccineBatchId,
      signature,
      { from : this.owner }
      );
      expectEvent(result.receipt, "IssueCertificate", {
        issuer:inspector.id,
        prover:manufacturerA.id,
        certificateId:new BN(0)
      });
 
      const retrievedCertificate = await this.coldChainInstance.certificates.call(0);
 
      assert.equal(retrievedCertificate.id, 0);
      assert.equal(retrievedCertificate.issuer["id"], inspector.id);
      assert.equal(retrievedCertificate.prover["id"], manufacturerA.id);
      assert.equal(retrievedCertificate.signature, signature);
      assert.equal(retrievedCertificate.status, this.StatusEnums.manufactured.pos.toString());
 
      // added entities, vaccine batches, signed vaccine bathes at client side and sent it to the blockchain and issues the certificate
 
      // now, we need to validate the signatue.
      // 1. imagine you are the distributor or verifier . validating if the inspector sign has been falsified or not.
 
  });
 
  it('should verify that the certificate signature matches the issuer', async () => {
    const {inspector, manufacturerA} = this.defaultEntities;
    const vaccineBatchId = 0;
    const message = `Inspector(${inspector.id}) has certified vaccine batch #${vaccineBatchId} for Manufacturer (${manufacturerA.id}).`;
    //const message = `Inspector has certified vaccine batch for Manufacturer (${manufacturerA.id}).`;
   
    const certificate = await this.coldChainInstance.certificates.call(0);
 
    const signerMatches = await this.coldChainInstance.isMatchingSignature(
      this.web3.utils.keccak256(message),
      certificate.id,
      inspector.id,
      { from : this.owner }
    );
    console.log(signerMatches);
    assert.equal(signerMatches, true, "can't verify");
  });
});

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.