signature
This commit is contained in:
parent
333c075ae7
commit
1a01674532
1
index.js
1
index.js
|
@ -19,6 +19,7 @@ privsec.point = require('./lib/point');
|
|||
privsec.privkey = require('./lib/privkey');
|
||||
privsec.pubkey = require('./lib/pubkey');
|
||||
privsec.random = require('./lib/random');
|
||||
privsec.signature = require('./lib/signature');
|
||||
|
||||
//privsec.script = require('lib/script');
|
||||
//privsec.scriptexec = require('lib/scriptexec');
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
var bn = require('./bn');
|
||||
|
||||
var Signature = function(r, s) {
|
||||
this.r = r;
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
Signature.prototype.fromCompressed = function(buf) {
|
||||
var b1 = buf.slice(0, 1)[0];
|
||||
var b2 = buf.slice(1, 33);
|
||||
var b3 = buf.slice(33, 65);
|
||||
|
||||
if (!(b1 === 0 || b1 === 1 || b1 === 2 || b1 === 3))
|
||||
throw new Error('signature: i must be 0, 1, 2, or 3');
|
||||
if (b2.length !== 32)
|
||||
throw new Error('signature: r must be 32 bytes');
|
||||
if (b3.length !== 32)
|
||||
throw new Error('signature: s must be 32 bytes');
|
||||
|
||||
this.r = bn.fromBuffer(b2);
|
||||
this.s = bn.fromBuffer(b3);
|
||||
};
|
||||
|
||||
Signature.prototype.fromDER = function(buf) {
|
||||
var obj = Signature.parseDER(buf);
|
||||
this.r = obj.r;
|
||||
this.s = obj.s;
|
||||
};
|
||||
|
||||
Signature.prototype.fromString = function(str) {
|
||||
var buf = new Buffer(str, 'hex');
|
||||
this.fromDER(buf);
|
||||
};
|
||||
|
||||
Signature.parseDER = function(buf) {
|
||||
if (!Buffer.isBuffer(buf))
|
||||
throw new Error('signature: DER formatted signature should be a buffer');
|
||||
|
||||
var header = buf[0];
|
||||
|
||||
if (header !== 0x30)
|
||||
throw new Error('signature: Header byte should be 0x30');
|
||||
|
||||
var length = buf[1];
|
||||
if (length !== buf.slice(2).length)
|
||||
throw new Error('signature: Length byte should length of what follows');
|
||||
|
||||
var rheader = buf[2 + 0];
|
||||
if (rheader !== 0x02)
|
||||
throw new Error('signature: Integer byte for r should be 0x02');
|
||||
|
||||
var rlength = buf[2 + 1];
|
||||
var rbuf = buf.slice(2 + 2, 2 + 2 + rlength);
|
||||
var r = bn.fromBuffer(rbuf);
|
||||
var rneg = buf[2 + 1 + 1] === 0x00 ? true : false;
|
||||
if (rlength !== rbuf.length)
|
||||
throw new Error('signature: Length of r incorrect');
|
||||
|
||||
var sheader = buf[2 + 2 + rlength + 0];
|
||||
if (sheader !== 0x02)
|
||||
throw new Error('signature: Integer byte for s should be 0x02');
|
||||
|
||||
var slength = buf[2 + 2 + rlength + 1];
|
||||
var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength);
|
||||
var s = bn.fromBuffer(sbuf);
|
||||
var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false;
|
||||
if (slength !== sbuf.length)
|
||||
throw new Error('signature: Length of s incorrect');
|
||||
|
||||
var sumlength = 2 + 2 + rlength + 2 + slength;
|
||||
if (length !== sumlength - 2)
|
||||
throw new Error('signature: Length of signature incorrect');
|
||||
|
||||
var obj = {
|
||||
header: header,
|
||||
length: length,
|
||||
rheader: rheader,
|
||||
rlength: rlength,
|
||||
rneg: rneg,
|
||||
rbuf: rbuf,
|
||||
r: r,
|
||||
sheader: sheader,
|
||||
slength: slength,
|
||||
sneg: sneg,
|
||||
sbuf: sbuf,
|
||||
s: s
|
||||
};
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
Signature.prototype.toCompressed = function(i) {
|
||||
if (!(i === 0 || i === 1 || i ===2 || i ===3))
|
||||
throw new Error('signature: i must be equal to 0, 1, 2, or 3');
|
||||
|
||||
var b1 = new Buffer([i]);
|
||||
var b2 = this.r.toBuffer({size: 32});
|
||||
var b3 = this.s.toBuffer({size: 32});
|
||||
return Buffer.concat([b1, b2, b3]);
|
||||
};
|
||||
|
||||
Signature.prototype.toDER = function() {
|
||||
var rnbuf = this.r.toBuffer();
|
||||
var snbuf = this.s.toBuffer();
|
||||
|
||||
var rneg = rnbuf[0] & 0x80 ? true : false;
|
||||
var sneg = snbuf[0] & 0x80 ? true : false;
|
||||
|
||||
var rbuf = rneg ? Buffer.concat([new Buffer([0x00]), rnbuf]) : rnbuf;
|
||||
var sbuf = sneg ? Buffer.concat([new Buffer([0x00]), snbuf]) : snbuf;
|
||||
|
||||
var length = 2 + rbuf.length + 2 + sbuf.length;
|
||||
var rlength = rbuf.length;
|
||||
var slength = sbuf.length;
|
||||
var rheader = 0x02;
|
||||
var sheader = 0x02;
|
||||
var header = 0x30;
|
||||
|
||||
var der = Buffer.concat([new Buffer([header, length, rheader, rlength]), rbuf, new Buffer([sheader, slength]), sbuf]);
|
||||
return der;
|
||||
};
|
||||
|
||||
Signature.prototype.toString = function() {
|
||||
var buf = this.toDER();
|
||||
return buf.toString('hex');
|
||||
};
|
||||
module.exports = Signature;
|
|
@ -0,0 +1,132 @@
|
|||
var bn = require('../lib/bn');
|
||||
var should = require('chai').should();
|
||||
var Signature = require('../lib/signature');
|
||||
|
||||
describe('Signature', function() {
|
||||
|
||||
it('should make a blank signature', function() {
|
||||
var sig = new Signature();
|
||||
should.exist(sig);
|
||||
});
|
||||
|
||||
describe('#fromCompressed', function() {
|
||||
|
||||
it('should create a signature from a compressed signature', function() {
|
||||
var blank = new Buffer(32);
|
||||
blank.fill(0);
|
||||
var compressed = Buffer.concat([
|
||||
new Buffer([0]),
|
||||
blank,
|
||||
blank
|
||||
]);
|
||||
var sig = new Signature();
|
||||
sig.fromCompressed(compressed);
|
||||
sig.r.cmp(0).should.equal(0);
|
||||
sig.s.cmp(0).should.equal(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#fromDER', function() {
|
||||
|
||||
var buf = new Buffer('3044022075fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e62770220729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2', 'hex');
|
||||
|
||||
it('should parse this DER format signature', function() {
|
||||
var sig = new Signature();
|
||||
sig.fromDER(buf);
|
||||
sig.r.toBuffer({size: 32}).toString('hex').should.equal('75fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e6277');
|
||||
sig.s.toBuffer({size: 32}).toString('hex').should.equal('729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#fromString', function() {
|
||||
|
||||
var buf = new Buffer('3044022075fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e62770220729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2', 'hex');
|
||||
|
||||
it('should parse this DER format signature in hex', function() {
|
||||
var sig = new Signature();
|
||||
sig.fromString(buf.toString('hex'));
|
||||
sig.r.toBuffer({size: 32}).toString('hex').should.equal('75fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e6277');
|
||||
sig.s.toBuffer({size: 32}).toString('hex').should.equal('729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseDER', function() {
|
||||
|
||||
it('should parse this signature generated in node', function() {
|
||||
var sighex = '30450221008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa02200993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72';
|
||||
var sig = new Buffer(sighex, 'hex');
|
||||
var parsed = Signature.parseDER(sig);
|
||||
parsed.header.should.equal(0x30)
|
||||
parsed.length.should.equal(69)
|
||||
parsed.rlength.should.equal(33);
|
||||
parsed.rneg.should.equal(true);
|
||||
parsed.rbuf.toString('hex').should.equal('008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa');
|
||||
parsed.r.toString().should.equal('63173831029936981022572627018246571655303050627048489594159321588908385378810');
|
||||
parsed.slength.should.equal(32);
|
||||
parsed.sneg.should.equal(false);
|
||||
parsed.sbuf.toString('hex').should.equal('0993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72');
|
||||
parsed.s.toString().should.equal('4331694221846364448463828256391194279133231453999942381442030409253074198130');
|
||||
});
|
||||
|
||||
it('should parse this 69 byte signature', function() {
|
||||
var sighex = '3043021f59e4705959cc78acbfcf8bd0114e9cc1b389a4287fb33152b73a38c319b50302202f7428a27284c757e409bf41506183e9e49dfb54d5063796dfa0d403a4deccfa';
|
||||
var sig = new Buffer(sighex, 'hex');
|
||||
var parsed = Signature.parseDER(sig);
|
||||
parsed.header.should.equal(0x30)
|
||||
parsed.length.should.equal(67)
|
||||
parsed.rlength.should.equal(31);
|
||||
parsed.rneg.should.equal(false);
|
||||
parsed.rbuf.toString('hex').should.equal('59e4705959cc78acbfcf8bd0114e9cc1b389a4287fb33152b73a38c319b503');
|
||||
parsed.r.toString().should.equal('158826015856106182499128681792325160381907915189052224498209222621383996675');
|
||||
parsed.slength.should.equal(32);
|
||||
parsed.sneg.should.equal(false);
|
||||
parsed.sbuf.toString('hex').should.equal('2f7428a27284c757e409bf41506183e9e49dfb54d5063796dfa0d403a4deccfa');
|
||||
parsed.s.toString().should.equal('21463938592353267769710297084836796652964571266930856168996063301532842380538');
|
||||
});
|
||||
|
||||
it('should parse this 68 byte signature', function() {
|
||||
var sighex = '3042021e17cfe77536c3fb0526bd1a72d7a8e0973f463add210be14063c8a9c37632022061bfa677f825ded82ba0863fb0c46ca1388dd3e647f6a93c038168b59d131a51';
|
||||
var sig = new Buffer(sighex, 'hex');
|
||||
var parsed = Signature.parseDER(sig);
|
||||
parsed.header.should.equal(0x30)
|
||||
parsed.length.should.equal(66)
|
||||
parsed.rlength.should.equal(30);
|
||||
parsed.rneg.should.equal(false);
|
||||
parsed.rbuf.toString('hex').should.equal('17cfe77536c3fb0526bd1a72d7a8e0973f463add210be14063c8a9c37632');
|
||||
parsed.r.toString().should.equal('164345250294671732127776123343329699648286106708464198588053542748255794');
|
||||
parsed.slength.should.equal(32);
|
||||
parsed.sneg.should.equal(false);
|
||||
parsed.sbuf.toString('hex').should.equal('61bfa677f825ded82ba0863fb0c46ca1388dd3e647f6a93c038168b59d131a51');
|
||||
parsed.s.toString().should.equal('44212963026209759051804639008236126356702363229859210154760104982946304432721');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#toDER', function() {
|
||||
|
||||
it('should convert these known r and s values into a known signature', function() {
|
||||
var r = bn('63173831029936981022572627018246571655303050627048489594159321588908385378810');
|
||||
var s = bn('4331694221846364448463828256391194279133231453999942381442030409253074198130');
|
||||
var sig = new Signature(r, s);
|
||||
var der = sig.toDER(r, s);
|
||||
der.toString('hex').should.equal('30450221008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa02200993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#toString', function() {
|
||||
|
||||
it('should convert this signature in to hex DER', function() {
|
||||
var r = bn('63173831029936981022572627018246571655303050627048489594159321588908385378810');
|
||||
var s = bn('4331694221846364448463828256391194279133231453999942381442030409253074198130');
|
||||
var sig = new Signature(r, s);
|
||||
var hex = sig.toString();
|
||||
hex.should.equal('30450221008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa02200993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue