Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 1 | /** |
| 2 | * @author: Wentao Shang |
| 3 | * See COPYING for copyright and distribution information. |
| 4 | */ |
| 5 | |
Jeff Thompson | 2b14c7e | 2013-07-29 15:09:56 -0700 | [diff] [blame] | 6 | /** |
| 7 | * @constructor |
| 8 | */ |
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 9 | var MerklePath = function MerkelPath() { |
| 10 | this.index = null; // int |
| 11 | this.digestList = []; // array of hex string |
| 12 | }; |
| 13 | |
Jeff Thompson | 2b14c7e | 2013-07-29 15:09:56 -0700 | [diff] [blame] | 14 | /** |
| 15 | * @constructor |
| 16 | */ |
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 17 | var Witness = function Witness() { |
| 18 | this.oid = null; // string |
| 19 | this.path = new MerklePath(); // MerklePath |
| 20 | }; |
| 21 | |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 22 | function parseOID(bytes, start, end) { |
| 23 | var s, n = 0, bits = 0; |
| 24 | for (var i = start; i < end; ++i) { |
| 25 | var v = bytes[i]; |
| 26 | n = (n << 7) | (v & 0x7F); |
| 27 | bits += 7; |
| 28 | if (!(v & 0x80)) { // finished |
| 29 | if (s == undefined) |
| 30 | s = parseInt(n / 40) + "." + (n % 40); |
| 31 | else |
| 32 | s += "." + ((bits >= 31) ? "bigint" : n); |
| 33 | n = bits = 0; |
| 34 | } |
| 35 | s += String.fromCharCode(); |
| 36 | } |
| 37 | return s; |
| 38 | } |
| 39 | |
| 40 | function parseInteger(bytes, start, end) { |
| 41 | var n = 0; |
| 42 | for (var i = start; i < end; ++i) |
| 43 | n = (n << 8) | bytes[i]; |
| 44 | return n; |
| 45 | } |
| 46 | |
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 47 | Witness.prototype.decode = function(/* Uint8Array */ witness) { |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 48 | /* The asn1.js decoder has some bug and |
| 49 | * cannot decode certain kind of witness. |
| 50 | * So we use an alternative (and dirty) hack |
| 51 | * to read witness from byte streams |
| 52 | * ------Wentao |
| 53 | */ |
| 54 | /* |
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 55 | var wit = DataUtils.toHex(witness).toLowerCase(); |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 56 | try { |
| 57 | var der = Hex.decode(wit); |
| 58 | var asn1 = ASN1.decode(der); |
| 59 | } |
| 60 | catch (e) { |
| 61 | console.log(e); |
| 62 | console.log(wit); |
| 63 | } |
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 64 | //console.log(asn1.toPrettyString()); |
| 65 | |
| 66 | this.oid = asn1.sub[0].sub[0].content(); // OID |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 67 | //console.log(this.oid); |
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 68 | this.path.index = asn1.sub[1].sub[0].sub[0].content(); // index |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 69 | //console.log(this.path.index); |
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 70 | for (i = 0; i < asn1.sub[1].sub[0].sub[1].sub.length; i++) { |
| 71 | pos = asn1.sub[1].sub[0].sub[1].sub[i].stream.pos; |
| 72 | str = wit.substring(2 * pos + 4, 2 * pos + 68); |
| 73 | this.path.digestList.push(str); // digest hex string |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 74 | //console.log(str); |
| 75 | } |
| 76 | */ |
| 77 | |
| 78 | // FIXME: Need to be fixed to support arbitrary ASN1 encoding, |
| 79 | // But do we really nned that???? -------Wentao |
| 80 | |
| 81 | // The structure of Witness is fixed as follows: |
| 82 | // SEQUENCE (2 elem) |
| 83 | // SEQUENCE (1 elem) |
| 84 | // OBJECT IDENTIFIER 1.2.840.113550.11.1.2.2 |
| 85 | // OCTET STRING (1 elem) |
| 86 | // SEQUENCE (2 elem) |
| 87 | // INTEGER index |
| 88 | // SEQUENCE (n elem) |
| 89 | // OCTET STRING(32 byte) 345FB4B5E9A1D2FF450ECA87EB87601683027A1A... |
| 90 | // OCTET STRING(32 byte) DBCEE5B7A6C2B851B029324197DDBD9A655723DC... |
| 91 | // OCTET STRING(32 byte) 4C79B2D256E4CD657A27F01DCB51AC3C56A24E71... |
| 92 | // OCTET STRING(32 byte) 7F7FB169604A87EAC94378F0BDB4FC5D5899AB88... |
| 93 | // ...... |
| 94 | // Hence we can follow this structure to extract witness fields at fixed level |
| 95 | // Tag numbers for ASN1: |
| 96 | // SEQUENCE 0x10 |
| 97 | // OCT STRING 0x04 |
| 98 | // INTEGER 0x02 |
| 99 | // OBJECT IDENTIFIER 0x06 |
| 100 | var i = 0; |
| 101 | var step = 0; // count of sequence tag |
| 102 | while (i < witness.length) { |
| 103 | var len = 0; |
| 104 | |
| 105 | if (witness[i] == 0x30) { |
| 106 | // Sequence (constructed) |
| 107 | // There is no primitive sequence in Witness |
| 108 | if ((witness[i + 1] & 0x80) != 0) { |
| 109 | len = witness[i+1] & 0x7F; |
| 110 | } |
| 111 | step++; |
| 112 | } else if (witness[i] == 0x06) { |
| 113 | // Decode OID |
| 114 | len = witness[i+1]; // XXX: OID will not be longer than 127 bytes |
| 115 | this.oid = parseOID(witness, i + 2, i + 2 + len); |
| 116 | //console.log(this.oid); |
| 117 | } else if (witness[i] == 0x02) { |
| 118 | // Decode node index |
| 119 | len = witness[i+1]; // XXX: index will not be longer than 127 bytes |
| 120 | this.path.index = parseInteger(witness, i + 2, i + 2 + len); |
| 121 | //console.log(this.path.index); |
| 122 | } else if (witness[i] == 0x04) { |
| 123 | if ((witness[i + 1] & 0x80) != 0) { |
| 124 | len = witness[i+1] & 0x7F; |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 125 | } |
| 126 | if (step == 4) { |
| 127 | // Start to decode digest hex string |
Wentao Shang | edd4dea | 2013-01-19 16:55:11 -0800 | [diff] [blame] | 128 | len = witness[i+1]; // XXX: digest hex should always be 32 bytes |
Jeff Thompson | 48ff28a | 2013-02-18 22:53:29 -0800 | [diff] [blame] | 129 | var str = DataUtils.toHex(witness.subarray(i + 2, i + 2 + len)); |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 130 | this.path.digestList.push(str); // digest hex string |
| 131 | //console.log(str); |
| 132 | } |
| 133 | } |
| 134 | i = i + 2 + len; |
Wentao Shang | 882e34e | 2013-01-05 02:49:51 -0800 | [diff] [blame] | 135 | } |
| 136 | }; |