Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Commit

Permalink
Handle additional signature component lengths (#4230)
Browse files Browse the repository at this point in the history
* Added ledger support

* Fixed block explorer

* Added CL args

* Added a flag to ignore balance check

* Fixed explorer test

* Minor changes as per feedback

* Minor changes as per feedback

* Added global.json to lock the version

* DOwngraded to 2.1

* Removed unused tests

* Added keypath param for advanced users

* Fixed address scanning

* Fix for index

* Added more logs

* Added more logs

* Added logic to scan change addresses

* Added more logs

* Added ability to output signature

* Added minimum balance check

* Handle case where the signature R component is only 31 bytes

* Handle R and S values of length 31, 32 or 33

* Fix brace

Co-authored-by: Igor Goldobin <igor.goldobin@bhp.com>
Co-authored-by: Igor Goldobin <igor.goldobin@gmail.com>
  • Loading branch information
3 people authored Jul 24, 2021
1 parent f19d6f9 commit 3a9d81b
Showing 1 changed file with 40 additions and 19 deletions.
59 changes: 40 additions & 19 deletions src/AddressOwnershipTool/LedgerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,59 +138,80 @@ private string GetSignature(string address, byte[] resp, PubKey pubKey)
Console.WriteLine($@"Signature response from ledger: {BitConverter.ToString(resp)}");
}

if (resp[0] != (byte)(48 + recId))
if (resp[0] != (byte) (48 + recId))
continue; //throw new Exception("Unexpected signature encoding - outer type not SET");

if (resp[2] != 0x02)
throw new Exception("Invalid signature encoding - type not integer");

int rLength = resp[3];

var rBytes = new byte[32];
Array.Resize(ref rBytes, rLength); // can be 33
byte[] rBytes = new byte[rLength];
Array.Copy(resp, 4, rBytes, 0, rLength);

if (resp[4 + rLength] != 0x02)
throw new Exception("Invalid signature encoding - type not integer");

int sLength = resp[5 + rLength];

var sBytes = new byte[32];
byte[] sBytes = new byte[sLength];
Array.Copy(resp, 6 + rLength, sBytes, 0, sLength);

// Now we have to work backwards to figure out the recId needed to recover the signature.

int headerByte = recId + 27 + (pubKey.IsCompressed ? 4 : 0);

var sigData = new byte[1 + rLength + sLength]; // 1 header + 32 bytes for R + 32 bytes for S
byte[] sigData = new byte[1 + 32 + 32]; // 1 header + 32 bytes for R + 32 bytes for S

sigData[0] = (byte)headerByte;
sigData[0] = (byte) headerByte;

if (rLength == 31)
switch (rLength)
{
Array.Copy(rBytes, 0, sigData, 1, 31);
Array.Copy(sBytes, sLength == 33 ? 1 : 0, sigData, 32, 32);
case 31:
// Add 1 to destination index as there will be a leading zero to make up the 32 bytes
Array.Copy(rBytes, 0, sigData, 1 + 1, rLength);
break;
case 32:
// The 'typical' case - no additional offsets
Array.Copy(rBytes, 0, sigData, 1 + 0, rLength);
break;
case 33:
// Use sourceIndex = 1 as we trim off the leading byte
Array.Copy(rBytes, 1, sigData, 1 + 0, rLength - 1);
break;
default:
throw new Exception("Unexpected rLength: " + rLength);
}
else

switch (sLength)
{
Array.Copy(rBytes, rLength == 33 ? 1 : 0, sigData, 1, 32);
Array.Copy(sBytes, sLength == 33 ? 1 : 0, sigData, 33, 32);
case 31:
Array.Copy(sBytes, 0, sigData, 33 + 1, sLength);
break;
case 32:
Array.Copy(sBytes, 0, sigData, 33 + 0, sLength);
break;
case 33:
Array.Copy(sBytes, 1, sigData, 33 + 0, sLength - 1);
break;
default:
throw new Exception("Unexpected sLength: " + sLength);
}

var specialBytes = 0x18;
var prefixBytes = Encoding.UTF8.GetBytes("Stratis Signed Message:\n");
var lengthBytes = BitConverter.GetBytes((char)address.Length).Take(1).ToArray();
var addressBytes = Encoding.UTF8.GetBytes(address);
int specialBytes = 0x18;
byte[] prefixBytes = Encoding.UTF8.GetBytes("Stratis Signed Message:\n");
byte[] lengthBytes = BitConverter.GetBytes((char) address.Length).Take(1).ToArray();
byte[] addressBytes = Encoding.UTF8.GetBytes(address);

byte[] dataBytes = new byte[1 + prefixBytes.Length + lengthBytes.Length + addressBytes.Length];
dataBytes[0] = (byte)specialBytes;
dataBytes[0] = (byte) specialBytes;
Buffer.BlockCopy(prefixBytes, 0, dataBytes, 1, prefixBytes.Length);
Buffer.BlockCopy(lengthBytes, 0, dataBytes, prefixBytes.Length + 1, lengthBytes.Length);
Buffer.BlockCopy(addressBytes, 0, dataBytes, prefixBytes.Length + lengthBytes.Length + 1, addressBytes.Length);

uint256 messageHash = NBitcoin.Crypto.Hashes.Hash256(dataBytes);
var recovered = PubKey.RecoverCompact(messageHash, sigData);
var recoveredAddress = recovered.Hash.ScriptPubKey.GetDestinationAddress(this.network).ToString();
PubKey recovered = PubKey.RecoverCompact(messageHash, sigData);
string recoveredAddress = recovered.Hash.ScriptPubKey.GetDestinationAddress(this.network).ToString();
bool foundMatch = recoveredAddress == address;

if (foundMatch)
Expand Down

0 comments on commit 3a9d81b

Please sign in to comment.