The problem is that eth.sign returns a signature where v is 0 or 1 and ecrecover expect it to be 27 or 28.
A note in the documentation for web3 v0.20 is clear:
Note that if you are using ecrecover, v will be either "00" or "01".
As a result, in order to use this value, you will have to parse it to
an integer and then add 27. This will result in ...
It's okay to define a contract instance every time you need it,
as the ABI and deployed address haven't changed, and your web3 library
or doing anything slow over the network.
I think the efficiency difference is negligible, but if you can create your contract instance once and pass it ...
The solution was to create and add the account from which to send the transaction into a wallet.
adding the line
above the method.send() fixed it for me.
Just in case someone comes here later, in the recent version of ethers, HDNODE has been moved to the utils method. So, in modification to @George's answer above;
const ethers = require('ethers');
const mnemonic = await ethers.utils.HDNode.entropyToMnemonic(ethers.utils.randomBytes(16));
const wallet = ethers.Wallet.fromMnemonic(mnemonic);