From c03d3c581859af67dcad58a2da5d4bfe898a6abf Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Thu, 27 Mar 2014 23:34:17 -0400 Subject: [PATCH] get BIP32 working in the browser by exposing more crypto --- Key.js | 12 ++++---- Point.js | 67 +++++++++++++++++++++++++++++++++++++++-- browser/vendor/ec.js | 3 ++ browser/vendor/jsbn2.js | 2 ++ browser/vendor/sec.js | 2 ++ test/test.BIP32.js | 1 + 6 files changed, 79 insertions(+), 8 deletions(-) diff --git a/Key.js b/Key.js index 4c880ab..f386a7b 100644 --- a/Key.js +++ b/Key.js @@ -10,7 +10,12 @@ if (process.versions) { var ECKey = require('./browser/vendor-bundle.js').ECKey; var buffertools = require('buffertools'); - var bufferToArray = function(buffer) { + var kSpec = function() { + this._pub = null; + this.compressed = true; // default + }; + + var bufferToArray = kSpec.bufferToArray = function(buffer) { var ret = []; var l = buffer.length; @@ -21,11 +26,6 @@ if (process.versions) { return ret; } - var kSpec = function() { - this._pub = null; - this.compressed = true; // default - }; - Object.defineProperty(kSpec.prototype, 'public', { set: function(p){ diff --git a/Point.js b/Point.js index b028e37..b18971d 100644 --- a/Point.js +++ b/Point.js @@ -1,6 +1,20 @@ +"use strict"; + var imports = require('soop').imports(); -var Key = imports.Key || require('./Key'); +var Key = imports.Key || require('./Key'); var bignum = imports.bignum || require('bignum'); +var assert = require('assert'); + +//browser +if (!process.versions) { + var ECKey = require('./browser/vendor-bundle.js').ECKey; + var ECPointFp = require('./browser/vendor-bundle.js').ECPointFp; + var ECFieldElementFp = require('./browser/vendor-bundle.js').ECFieldElementFp; + var getSECCurveByName = require('./browser/vendor-bundle.js').getSECCurveByName; + var BigInteger = require('./browser/vendor-bundle.js').BigInteger; + var should = require('chai').should(); +} + //a point on the secp256k1 curve //x and y are bignums @@ -27,6 +41,35 @@ Point.add = function(p1, p2) { //browser else { + var ecparams = getSECCurveByName('secp256k1'); + + var p1xhex = p1.x.toBuffer({size: 32}).toString('hex'); + var p1x = new BigInteger(p1xhex, 16); + var p1yhex = p1.y.toBuffer({size: 32}).toString('hex'); + var p1y = new BigInteger(p1yhex, 16); + var p1px = new ECFieldElementFp(ecparams.getCurve().getQ(), p1x); + var p1py = new ECFieldElementFp(ecparams.getCurve().getQ(), p1y); + var p1p = new ECPointFp(ecparams.getCurve(), p1px, p1py); + + var p2xhex = p2.x.toBuffer({size: 32}).toString('hex'); + var p2x = new BigInteger(p2xhex, 16); + var p2yhex = p2.y.toBuffer({size: 32}).toString('hex'); + var p2y = new BigInteger(p2yhex, 16); + var p2px = new ECFieldElementFp(ecparams.getCurve().getQ(), p2x); + var p2py = new ECFieldElementFp(ecparams.getCurve().getQ(), p2y); + var p2p = new ECPointFp(ecparams.getCurve(), p2px, p2py); + + var p = p1p.add(p2p); + + var point = new Point(); + var pointxbuf = new Buffer(p.getX().toBigInteger().toByteArrayUnsigned()); + point.x = bignum.fromBuffer(pointxbuf, {size: pointxbuf.length}); + assert(pointxbuf.length <= 32); + var pointybuf = new Buffer(p.getY().toBigInteger().toByteArrayUnsigned()); + assert(pointybuf.length <= 32); + point.y = bignum.fromBuffer(pointybuf, {size: pointybuf.length}); + + return point; } }; @@ -49,6 +92,15 @@ Point.fromKey = function(key) { //browser else { + var point = new Point(); + var pubKeyBuf = new Buffer(key.public); + var key2 = new ECKey(); + key2.setCompressed(key.compressed); + key2.setPub(Key.bufferToArray(pubKeyBuf)); + key2.setCompressed(false); + point.x = bignum.fromBuffer((new Buffer(key2.getPub())).slice(1, 33), {size: 32}); + point.y = bignum.fromBuffer((new Buffer(key2.getPub())).slice(33, 65), {size: 32}); + return point; } }; @@ -62,13 +114,24 @@ Point.prototype.toKey = function() { var key = new Key(); key.compressed = false; var prefix = new Buffer([0x04]); - key.public = Buffer.concat([prefix, xbuf, ybuf]); //this is probably wrong + key.public = Buffer.concat([prefix, xbuf, ybuf]); //this might be wrong key.compressed = true; return key; } //browser else { + var xbuf = this.x.toBuffer({size: 32}); + var ybuf = this.y.toBuffer({size: 32}); + var key = new ECKey(); + key.setCompressed(false); + var prefix = new Buffer([0x04]); + var pub = Buffer.concat([prefix, xbuf, ybuf]); //this might be wrong + key.setPub(Key.bufferToArray(pub)); + key.setCompressed(true); + var key2 = new Key(); + key2.public = new Buffer(key.getPub()); + return key2; } }; diff --git a/browser/vendor/ec.js b/browser/vendor/ec.js index 43ded3e..4fb77e6 100644 --- a/browser/vendor/ec.js +++ b/browser/vendor/ec.js @@ -314,3 +314,6 @@ ECCurveFp.prototype.equals = curveFpEquals; ECCurveFp.prototype.getInfinity = curveFpGetInfinity; ECCurveFp.prototype.fromBigInteger = curveFpFromBigInteger; ECCurveFp.prototype.decodePointHex = curveFpDecodePointHex; + +module.exports.ECPointFp = ECPointFp; +module.exports.ECFieldElementFp = ECFieldElementFp; diff --git a/browser/vendor/jsbn2.js b/browser/vendor/jsbn2.js index 5b2b725..e9ff490 100644 --- a/browser/vendor/jsbn2.js +++ b/browser/vendor/jsbn2.js @@ -654,3 +654,5 @@ BigInteger.prototype.square = bnSquare; // int hashCode() // long longValue() // static BigInteger valueOf(long val) + +module.exports.BigInteger = BigInteger; diff --git a/browser/vendor/sec.js b/browser/vendor/sec.js index e496571..57ee936 100644 --- a/browser/vendor/sec.js +++ b/browser/vendor/sec.js @@ -171,3 +171,5 @@ function getSECCurveByName(name) { if(name == "secp256r1") return secp256r1(); return null; } + +module.exports.getSECCurveByName = getSECCurveByName; diff --git a/test/test.BIP32.js b/test/test.BIP32.js index 94188b4..122bd16 100644 --- a/test/test.BIP32.js +++ b/test/test.BIP32.js @@ -94,6 +94,7 @@ describe('BIP32', function() { }); it("should get m/0'/1 ext. public key from m/0' public key from test vector 1", function() { + //TEST var bip32 = new BIP32(vector1_m_private); var child = bip32.derive("m/0'"); var child_pub = new BIP32(child.extendedPublicKeyString());