Skip to content

Commit

Permalink
add feature: SignatureContext;
Browse files Browse the repository at this point in the history
  • Loading branch information
Erik Zhang committed Jul 19, 2016
1 parent 293c367 commit 1a4c62b
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
77 changes: 77 additions & 0 deletions sdk/AntShares/Core/SignatureContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
namespace AntShares.Core
{
export class SignatureContext
{
public signable: ISignable;
public scriptHashes: Uint160[];
private redeemScripts: ArrayBuffer[];
private signatures: Map<string, ArrayBuffer>[];
private completed: boolean[];

public add(contract: Wallets.Contract, pubkey: Cryptography.ECPoint, signature: ArrayBuffer): boolean
{
for (let i = 0; i < this.scriptHashes.length; i++)
{
if (this.scriptHashes[i].equals(contract.scriptHash))
{
if (this.redeemScripts[i] == null)
this.redeemScripts[i] = contract.redeemScript;
if (this.signatures[i] == null)
this.signatures[i] = new Map<string, ArrayBuffer>();
this.signatures[i].set(pubkey.toString(), signature);
let completed = contract.parameterList.length == this.signatures[i].size;
for (let j = 0; j < contract.parameterList.length && completed; j++)
if (contract.parameterList[j] != Wallets.ContractParameterType.Signature)
completed = false;
this.completed[i] = this.completed[i] || completed;
return true;
}
}
return false;
}

public static create(signable: ISignable): PromiseLike<SignatureContext>
{
return signable.getScriptHashesForVerifying().then(result =>
{
let context = new SignatureContext();
context.signable = signable;
context.scriptHashes = result;
context.redeemScripts = new Array<ArrayBuffer>(result.length);
context.signatures = new Array<Map<string, ArrayBuffer>>(result.length);
context.completed = new Array<boolean>(result.length);
return context;
});
}

public getScripts(): Core.Scripts.Script[]
{
if (!this.isCompleted()) throw new Error();
let scripts = new Array<Core.Scripts.Script>(this.signatures.length);
for (let i = 0; i < scripts.length; i++)
{
let array = new Array<{ pubkey: Cryptography.ECPoint, signature: ArrayBuffer }>();
this.signatures[i].forEach((signature, key) =>
{
array.push({ pubkey: Cryptography.ECPoint.parse(key, Cryptography.ECCurve.secp256r1), signature: signature });
});
array.sort((a, b) => a.pubkey.compareTo(b.pubkey));
let sb = new Core.Scripts.ScriptBuilder();
for (let j = 0; j < array.length; j++)
sb.push(array[j].signature);
scripts[i] = new Core.Scripts.Script();
scripts[i].stackScript = sb.toArray();
scripts[i].redeemScript = this.redeemScripts[i];
}
return scripts;
}

public isCompleted(): boolean
{
for (let i = 0; i < this.completed.length; i++)
if (!this.completed[i])
return false;
return true;
}
}
}
43 changes: 43 additions & 0 deletions sdk/AntShares/Wallets/Wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,49 @@
});
}

public sign(context: Core.SignatureContext): PromiseLike<boolean>
{
let promises = new Array<PromiseLike<{ contract: Contract, account: Account, signature: ArrayBuffer }>>();
for (let i = 0; i < context.scriptHashes.length; i++)
{
let contract = this.getContract(context.scriptHashes[i]);
if (contract == null) continue;
let account = this.getAccountByScriptHash(context.scriptHashes[i]);
if (account == null) continue;
promises.push(this.signInternal(context.signable, account).then(result =>
{
return { contract: contract, account: account, signature: result };
}));
}
return Promise.all(promises).then(results =>
{
let fSuccess = false;
for (let i = 0; i < results.length; i++)
{
fSuccess = fSuccess || context.add(results[i].contract, results[i].account.publicKey, results[i].signature);
}
return fSuccess;
});
}

private signInternal(signable: Core.ISignable, account: Account): PromiseLike<ArrayBuffer>
{
let pubkey = account.publicKey.encodePoint(false);
let d = new Uint8Array(account.privateKey).base64UrlEncode();
let x = pubkey.subarray(1, 33).base64UrlEncode();
let y = pubkey.subarray(33, 65).base64UrlEncode();
let ms = new IO.MemoryStream();
let writer = new IO.BinaryWriter(ms);
signable.serializeUnsigned(writer);
return Promise.all<any>([
window.crypto.subtle.importKey("jwk", <any>{ kty: "EC", crv: "P-256", d: d, x: x, y: y, ext: true }, { name: "ECDSA", namedCurve: "P-256" }, false, ["sign"]),
window.crypto.subtle.digest("SHA-256", ms.toArray())
]).then(results =>
{
return window.crypto.subtle.sign({ name: "ECDSA", hash: { name: "SHA-256" } }, results[0], results[1]);
});
}

public static toAddress(scriptHash: Uint160): PromiseLike<string>
{
let data = new Uint8Array(25);
Expand Down

0 comments on commit 1a4c62b

Please sign in to comment.