Initial from bip32.github.io
This commit is contained in:
121
js/bitcoinsig.js
Normal file
121
js/bitcoinsig.js
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
bitcoinsig.js - sign and verify messages with bitcoin address (public domain)
|
||||
*/
|
||||
|
||||
function msg_numToVarInt(i) {
|
||||
if (i < 0xfd) {
|
||||
return [i];
|
||||
} else if (i <= 0xffff) {
|
||||
// can't use numToVarInt from bitcoinjs, BitcoinQT wants big endian here (!)
|
||||
return [0xfd, i & 255, i >>> 8];
|
||||
} else {
|
||||
throw ("message too large");
|
||||
}
|
||||
}
|
||||
|
||||
function msg_bytes(message) {
|
||||
var b = Crypto.charenc.UTF8.stringToBytes(message);
|
||||
return msg_numToVarInt(b.length).concat(b);
|
||||
}
|
||||
|
||||
function msg_digest(message) {
|
||||
var b = msg_bytes("Bitcoin Signed Message:\n").concat(msg_bytes(message));
|
||||
return Crypto.SHA256(Crypto.SHA256(b, {asBytes:true}), {asBytes:true});
|
||||
}
|
||||
|
||||
function verify_message(signature, message, addrtype) {
|
||||
try {
|
||||
var sig = Crypto.util.base64ToBytes(signature);
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sig.length != 65)
|
||||
return false;
|
||||
|
||||
// extract r,s from signature
|
||||
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1,1+32));
|
||||
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33,33+32));
|
||||
|
||||
// get recid
|
||||
var compressed = false;
|
||||
var nV = sig[0];
|
||||
if (nV < 27 || nV >= 35)
|
||||
return false;
|
||||
if (nV >= 31) {
|
||||
compressed = true;
|
||||
nV -= 4;
|
||||
}
|
||||
var recid = BigInteger.valueOf(nV - 27);
|
||||
|
||||
var ecparams = getSECCurveByName("secp256k1");
|
||||
var curve = ecparams.getCurve();
|
||||
var a = curve.getA().toBigInteger();
|
||||
var b = curve.getB().toBigInteger();
|
||||
var p = curve.getQ();
|
||||
var G = ecparams.getG();
|
||||
var order = ecparams.getN();
|
||||
|
||||
var x = r.add(order.multiply(recid.divide(BigInteger.valueOf(2))));
|
||||
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
|
||||
var beta = alpha.modPow(p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)), p);
|
||||
var y = beta.subtract(recid).isEven() ? beta : p.subtract(beta);
|
||||
|
||||
var R = new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
|
||||
var e = BigInteger.fromByteArrayUnsigned(msg_digest(message));
|
||||
var minus_e = e.negate().mod(order);
|
||||
var inv_r = r.modInverse(order);
|
||||
var Q = (R.multiply(s).add(G.multiply(minus_e))).multiply(inv_r);
|
||||
|
||||
var public_key = Q.getEncoded(compressed);
|
||||
var addr = new Bitcoin.Address(Bitcoin.Util.sha256ripe160(public_key));
|
||||
|
||||
addr.version = addrtype ? addrtype : 0;
|
||||
return addr.toString();
|
||||
}
|
||||
|
||||
function sign_message(private_key, message, compressed, addrtype) {
|
||||
if (!private_key)
|
||||
return false;
|
||||
|
||||
var signature = private_key.sign(msg_digest(message));
|
||||
var address = new Bitcoin.Address(private_key.getPubKeyHash());
|
||||
address.version = addrtype ? addrtype : 0;
|
||||
|
||||
//convert ASN.1-serialized signature to bitcoin-qt format
|
||||
var obj = Bitcoin.ECDSA.parseSig(signature);
|
||||
var sequence = [0];
|
||||
sequence = sequence.concat(obj.r.toByteArrayUnsigned());
|
||||
sequence = sequence.concat(obj.s.toByteArrayUnsigned());
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var nV = 27 + i;
|
||||
if (compressed)
|
||||
nV += 4;
|
||||
sequence[0] = nV;
|
||||
var sig = Crypto.util.bytesToBase64(sequence);
|
||||
if (verify_message(sig, message, addrtype) == address)
|
||||
return sig;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function bitcoinsig_test() {
|
||||
var k = '5JeWZ1z6sRcLTJXdQEDdB986E6XfLAkj9CgNE4EHzr5GmjrVFpf';
|
||||
var a = '17mDAmveV5wBwxajBsY7g1trbMW1DVWcgL';
|
||||
var s = 'HDiv4Oe9SjM1FFVbKk4m3N34efYiRgkQGGoEm564ldYt44jHVTuX23+WnihNMi4vujvpUs1M529P3kftjDezn9E=';
|
||||
var m = 'test message';
|
||||
payload = Bitcoin.Base58.decode(k);
|
||||
secret = payload.slice(1, 33);
|
||||
compressed = payload.length == 38;
|
||||
console.log(verify_message(s, m));
|
||||
sig = sign_message(new Bitcoin.ECKey(secret), m, compressed);
|
||||
console.log(verify_message(sig, m));
|
||||
}
|
||||
|
||||
if (typeof require != 'undefined' && require.main === module) {
|
||||
window = global; navigator = {}; Bitcoin = {};
|
||||
eval(require('fs').readFileSync('./bitcoinjs-min.js')+'');
|
||||
eval(require('path').basename(module.filename,'.js')+'_test()');
|
||||
}
|
||||
Reference in New Issue
Block a user