Implement new Witness decoding function
diff --git a/js/security/Witness.js b/js/security/Witness.js
index 3b88f06..1a8c5e0 100644
--- a/js/security/Witness.js
+++ b/js/security/Witness.js
@@ -13,17 +13,119 @@
this.path = new MerklePath(); // MerklePath
};
+function parseOID(bytes, start, end) {
+ var s, n = 0, bits = 0;
+ for (var i = start; i < end; ++i) {
+ var v = bytes[i];
+ n = (n << 7) | (v & 0x7F);
+ bits += 7;
+ if (!(v & 0x80)) { // finished
+ if (s == undefined)
+ s = parseInt(n / 40) + "." + (n % 40);
+ else
+ s += "." + ((bits >= 31) ? "bigint" : n);
+ n = bits = 0;
+ }
+ s += String.fromCharCode();
+ }
+ return s;
+}
+
+function parseInteger(bytes, start, end) {
+ var n = 0;
+ for (var i = start; i < end; ++i)
+ n = (n << 8) | bytes[i];
+ return n;
+}
+
Witness.prototype.decode = function(/* Uint8Array */ witness) {
+ /* The asn1.js decoder has some bug and
+ * cannot decode certain kind of witness.
+ * So we use an alternative (and dirty) hack
+ * to read witness from byte streams
+ * ------Wentao
+ */
+ /*
var wit = DataUtils.toHex(witness).toLowerCase();
- var der = Hex.decode(wit);
- var asn1 = ASN1.decode(der);
+ try {
+ var der = Hex.decode(wit);
+ var asn1 = ASN1.decode(der);
+ }
+ catch (e) {
+ console.log(e);
+ console.log(wit);
+ }
//console.log(asn1.toPrettyString());
this.oid = asn1.sub[0].sub[0].content(); // OID
+ //console.log(this.oid);
this.path.index = asn1.sub[1].sub[0].sub[0].content(); // index
+ //console.log(this.path.index);
for (i = 0; i < asn1.sub[1].sub[0].sub[1].sub.length; i++) {
pos = asn1.sub[1].sub[0].sub[1].sub[i].stream.pos;
str = wit.substring(2 * pos + 4, 2 * pos + 68);
this.path.digestList.push(str); // digest hex string
+ //console.log(str);
+ }
+ */
+
+ // FIXME: Need to be fixed to support arbitrary ASN1 encoding,
+ // But do we really nned that???? -------Wentao
+
+ // The structure of Witness is fixed as follows:
+ // SEQUENCE (2 elem)
+ // SEQUENCE (1 elem)
+ // OBJECT IDENTIFIER 1.2.840.113550.11.1.2.2
+ // OCTET STRING (1 elem)
+ // SEQUENCE (2 elem)
+ // INTEGER index
+ // SEQUENCE (n elem)
+ // OCTET STRING(32 byte) 345FB4B5E9A1D2FF450ECA87EB87601683027A1A...
+ // OCTET STRING(32 byte) DBCEE5B7A6C2B851B029324197DDBD9A655723DC...
+ // OCTET STRING(32 byte) 4C79B2D256E4CD657A27F01DCB51AC3C56A24E71...
+ // OCTET STRING(32 byte) 7F7FB169604A87EAC94378F0BDB4FC5D5899AB88...
+ // ......
+ // Hence we can follow this structure to extract witness fields at fixed level
+ // Tag numbers for ASN1:
+ // SEQUENCE 0x10
+ // OCT STRING 0x04
+ // INTEGER 0x02
+ // OBJECT IDENTIFIER 0x06
+ var i = 0;
+ var step = 0; // count of sequence tag
+ while (i < witness.length) {
+ var len = 0;
+
+ if (witness[i] == 0x30) {
+ // Sequence (constructed)
+ // There is no primitive sequence in Witness
+ if ((witness[i + 1] & 0x80) != 0) {
+ len = witness[i+1] & 0x7F;
+ }
+ step++;
+ } else if (witness[i] == 0x06) {
+ // Decode OID
+ len = witness[i+1]; // XXX: OID will not be longer than 127 bytes
+ this.oid = parseOID(witness, i + 2, i + 2 + len);
+ //console.log(this.oid);
+ } else if (witness[i] == 0x02) {
+ // Decode node index
+ len = witness[i+1]; // XXX: index will not be longer than 127 bytes
+ this.path.index = parseInteger(witness, i + 2, i + 2 + len);
+ //console.log(this.path.index);
+ } else if (witness[i] == 0x04) {
+ if ((witness[i + 1] & 0x80) != 0) {
+ len = witness[i+1] & 0x7F;
+ } else {
+ len = witness[i+1];
+ }
+ if (step == 4) {
+ // Start to decode digest hex string
+ str = DataUtils.toHex(witness.subarray(i + 2, i + 2 + len));
+ this.path.digestList.push(str); // digest hex string
+ //console.log(str);
+ }
+ }
+ i = i + 2 + len;
}
};