UNPKG

nel-neo-thinsdk

Version:
100 lines (94 loc) 4.12 kB
namespace Neo.Cryptography { export class ECDsa { constructor(private key: ECDsaCryptoKey) { } private static calculateE(n: BigInteger, message: ArrayBuffer | ArrayBufferView): BigInteger { return BigInteger.fromUint8Array(new Uint8Array(Sha256.computeHash(message)), 1, false); } public static generateKey(curve: ECCurve): { privateKey: ECDsaCryptoKey, publicKey: ECDsaCryptoKey } { let prikey = new Uint8Array(32); window.crypto.getRandomValues(prikey); let pubkey = ECPoint.multiply(curve.G, prikey); return { privateKey: new ECDsaCryptoKey(pubkey, prikey), publicKey: new ECDsaCryptoKey(pubkey) }; } public sign(message: ArrayBuffer | ArrayBufferView): ArrayBuffer { if (this.key.privateKey == null) throw new Error(); let e = ECDsa.calculateE(this.key.publicKey.curve.N, message); let d = BigInteger.fromUint8Array(this.key.privateKey, 1, false); let r: BigInteger, s: BigInteger; do { let k: BigInteger; do { do { k = BigInteger.random(this.key.publicKey.curve.N.bitLength()); } while (k.sign() == 0 || k.compareTo(this.key.publicKey.curve.N) >= 0); let p = ECPoint.multiply(this.key.publicKey.curve.G, k); let x = p.x.value; r = x.mod(this.key.publicKey.curve.N); } while (r.sign() == 0); s = k.modInverse(this.key.publicKey.curve.N).multiply(e.add(d.multiply(r))).mod(this.key.publicKey.curve.N); if (s.compareTo(this.key.publicKey.curve.N.divide(2)) > 0) { s = this.key.publicKey.curve.N.subtract(s); } } while (s.sign() == 0); let arr = new Uint8Array(64); Array.copy(r.toUint8Array(false, 32), 0, arr, 0, 32); Array.copy(s.toUint8Array(false, 32), 0, arr, 32, 32); return arr.buffer; } private static sumOfTwoMultiplies(P: ECPoint, k: BigInteger, Q: ECPoint, l: BigInteger): ECPoint { let m = Math.max(k.bitLength(), l.bitLength()); let Z = ECPoint.add(P, Q); let R = P.curve.Infinity; for (let i = m - 1; i >= 0; --i) { R = R.twice(); if (k.testBit(i)) { if (l.testBit(i)) R = ECPoint.add(R, Z); else R = ECPoint.add(R, P); } else { if (l.testBit(i)) R = ECPoint.add(R, Q); } } return R; } public verify(message: ArrayBuffer | ArrayBufferView, signature: ArrayBuffer | ArrayBufferView): boolean { let arr = Uint8Array.fromArrayBuffer(signature); let r = BigInteger.fromUint8Array(arr.subarray(0, 32), 1, false); let s = BigInteger.fromUint8Array(arr.subarray(32, 64), 1, false); if (r.compareTo(this.key.publicKey.curve.N) >= 0 || s.compareTo(this.key.publicKey.curve.N) >= 0) return false; let e = ECDsa.calculateE(this.key.publicKey.curve.N, message); let c = s.modInverse(this.key.publicKey.curve.N); let u1 = e.multiply(c).mod(this.key.publicKey.curve.N); let u2 = r.multiply(c).mod(this.key.publicKey.curve.N); let point = ECDsa.sumOfTwoMultiplies(this.key.publicKey.curve.G, u1, this.key.publicKey, u2); let v = point.x.value.mod(this.key.publicKey.curve.N); return v.equals(r); } } }