Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cannot reproduce secp256k1 signature integration tests #7

Open
mutsys opened this issue Nov 1, 2017 · 1 comment
Open

cannot reproduce secp256k1 signature integration tests #7

mutsys opened this issue Nov 1, 2017 · 1 comment

Comments

@mutsys
Copy link

mutsys commented Nov 1, 2017

Hi there,

I am having some difficulty with the Secp256k1.validateSignature function. In order to debug this, I created a simple test contact:

contract Test {

    function validateSignature(bytes32 message, uint[2] signature, uint[2] publicKey) public pure returns (bool) {
        return Secp256k1.validateSignature(message, signature, publicKey);
    }

}

which I run from within a mocha test via truffle

const chai = require("chai");
const expect = chai.expect;

const Test = artifacts.require("Test");

contract("Test", accounts => {
    it("should validate a signature", done => {
        Test.deployed()
            .then(instance => {
                const message = ...;
                const signature = ...;
                const publicKey = ...;
                return instance.validateSignature.call(message, signature, publicKey);
            })
            .then(result => {
                expect(result).to.be.true;
                done();
            })
            .catch(error => {
                console.error(error);
                done(error);
            });
    });
});

The test succeeds as expected using any set of messages/signatures/publicKeys in your integration test data, however it fails 100% of the time when I try to use my own values for the arguments. The equivalent works just fine for me using the elliptic npm package.

const crypto = require("crypto");
const EC = require("elliptic").ec;
const ec = new EC("secp256k1");

const createKeyPair = () => {
    const keyPair = ec.genKeyPair();
    return {
        privateKey: keyPair.getPrivate("hex"),
        publicKey: keyPair.getPublic("hex")
    };
};

const message = "this is a message to sign";
const messageHash = crypto.createHash("sha256").update(message).digest("hex");
const keyPair = createKeyPair();
const signature = ec.sign(messageHash, keyPair.privateKey);
const verified = ec.verify(messageHash, signature, keyPair.publicKey, "hex");

But when I use this in the context of the test calling Secp256k1.validateSignature, it fails 100% of the time.

const chai = require("chai");
const expect = chai.expect;
const crypto = require("crypto");
const EC = require("elliptic").ec;
const Signature = require("elliptic/lib/elliptic/ec/signature");
const ec = new EC("secp256k1");

const Test = artifacts.require("Test");

const createKeyPair = () => {
    const keyPair = ec.genKeyPair();
    return {
        privateKey: keyPair.getPrivate("hex"),
        publicKey: keyPair.getPublic("hex")
    };
};

const signMessage = (message, privateKey) => {
    return ec.sign(message, privateKey).toDER("hex");
};

const parsePublicKey = (publicKeyBytesHex) => {
    const publicKey = ec.keyFromPublic(publicKeyBytesHex, "hex").getPublic();
    return {
        x: `0x${publicKey.x.toString(16)}`,
        y: `0x${publicKey.y.toString(16)}`
    };
}

const parseSignature = (signatureBytesHex) => {
    const signature = new Signature(signatureBytesHex, "hex");
    return {
        r: `0x${signature.r.toString(16)}`,
        s: `0x${signature.s.toString(16)}`
    };
};

const publicKeyToArray = (publicKey) => {
    const xy = parsePublicKey(publicKey);
    return [xy.x, xy.y];
};

const signatureToArray = (signature) => {
    const rs = parseSignature(signature);
    return [rs.r, rs.s];
};

const message = "this is a message to sign";
const messageHash = crypto.createHash("sha256").update(message).digest("hex");
const keyPair = createKeyPair();
const signature = signatureToArray(signMessage(messageHash, keyPair.privateKey));
const publicKey = publicKeyToArray(keyPair.publicKey);

contract("Test", accounts => {
    it("should validate a signature", done => {
        Test.deployed()
            .then(instance => {
                return instance.validateSignature.call("0x" + messageHash, signature, publicKey);
            })
            .then(result => {
                expect(result).to.be.true;
                done();
            })
            .catch(error => {
                console.error(error);
                done(error);
            });
    });
});

I'm kind of puzzled. This approach has worked for me consistently across a varierty of other languages and crypto implementations, just not here. I am guessing that I am not correctly creating the value that I am passing as the first argument of `Secp256k1.validateSignature`. Are you able to recognize any errors in my test?
@danaki
Copy link

danaki commented Jul 30, 2018

Can confirm, can't verify signed messages, hence tests are working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants