Skip to content

refactor(utxo-core): trimMessagePrefix fix function #6380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions modules/utxo-core/src/paygo/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './parsePayGoAttestation';
export * from './psbt';
export * from './trimMessagePrefix';
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ import * as utxolib from '@bitgo/utxo-lib';

/** We receive a proof in the form:
* 0x18Bitcoin Signed Message:\n<varint_length><ENTROPY><ADDRESS><UUID>
* and when verifying our message we want to exclude the 0x18Bitcoin Signed Message:\n<varint_length>
* of the proof so that we are left with the entropy address and uuid as our message.
* This is what we are going to be verifying.
* and trims the 0x18Bitcoin Signed Message:\n<varin_length> and returns
* our message <ENTROPY><ADDRESS><UUID> in a Buffer.
*
* @param proof
* @returns
*/
export function trimMessagePrefix(proof: Buffer): Buffer {
const prefix = '\u0018Bitcoin Signed Message:\n';
const prefixBuffer = Buffer.from(prefix, 'utf-8');
if (proof.toString().startsWith(prefix)) {
proof = proof.slice(Buffer.from(prefix).length);
proof = proof.slice(prefixBuffer.length);
utxolib.bufferutils.varuint.decode(proof, 0);
// Determines how many bytes were consumed during our last varuint.decode(Buffer, offset)
// So if varuint.decode(0xfd) then varuint.decode.bytes = 3
// varuint.decode(0xfe) then varuint.decode.bytes = 5, etc.
const varintBytesLength = utxolib.bufferutils.varuint.decode.bytes;

proof.slice(varintBytesLength);
return proof.slice(varintBytesLength);
}
return proof;
}
1 change: 0 additions & 1 deletion modules/utxo-core/src/testutil/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ export * from './fixtures.utils';
export * from './key.utils';
export * from './toPlainObject.utils';
export * from './generatePayGoAttestationProof.utils';
export * from './trimMessagePrefix';
44 changes: 40 additions & 4 deletions modules/utxo-core/test/paygo/psbt/payGoAddressProof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import {
verifyPayGoAddressProof,
} from '../../../src/paygo/psbt/payGoAddressProof';
import { generatePayGoAttestationProof } from '../../../src/testutil/generatePayGoAttestationProof.utils';
import { trimMessagePrefix } from '../../../src/testutil/trimMessagePrefix';
import { trimMessagePrefix } from '../../../src/paygo/trimMessagePrefix';
import { signMessage } from '../../../src/bip32utils';
import { NIL_UUID } from '../../../src/paygo/attestation';
import { createPayGoAttestationBuffer, NIL_UUID } from '../../../src/paygo/attestation';
import { parsePayGoAttestation } from '../../../src/paygo';

// To construct our PSBTs
export const network = utxolib.networks.bitcoin;
Expand Down Expand Up @@ -46,9 +47,11 @@ export const addressToVerify = utxolib.address.toBase58Check(

// this should be retuning a Buffer
export const addressProofBuffer = generatePayGoAttestationProof(NIL_UUID, Buffer.from(addressToVerify));

export const addressProofMsgBuffer = trimMessagePrefix(addressProofBuffer);
// We know that that the entropy is a set 64 bytes.
export const addressProofEntropy = addressProofMsgBuffer.subarray(0, 65);
const payGoAttestationProofComponents = parsePayGoAttestation(addressProofBuffer);

export const addressProofEntropy = payGoAttestationProofComponents.entropy;

// signature with the given msg addressProofBuffer
export const sig = signMessage(addressProofMsgBuffer.toString(), attestationPrvKey!, network);
Expand Down Expand Up @@ -131,3 +134,36 @@ describe('getPaygoAddressProofIndex', () => {
);
});
});

describe('trimMessagePrefix', function () {
it('should be the same proof constructed consistently', function () {
const psbt = getTestPsbt();
psbt.addOutput({ script: utxolib.address.toOutputScript(addressToVerify, network), value: BigInt(10000) });
const outputIndex = psbt.data.outputs.length - 1;
addPayGoAddressProof(psbt, outputIndex, sig, addressProofEntropy);
// manually check without the verify function to see if the entropy being stored
// in the psbt is the same as the entropy being extracted and trimmed.
const psbtOutputs = checkForOutput(psbt.data.outputs, outputIndex);
const stored = utxolib.bitgo.getProprietaryKeyValuesFromUnknownKeyValues(psbtOutputs, {
identifier: utxolib.bitgo.PSBT_PROPRIETARY_IDENTIFIER,
subtype: utxolib.bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF,
});

assert(stored[0].key.keydata.equals(payGoAttestationProofComponents.entropy));
assert(stored[0].value.equals(sig));

const reconstructedProofFromComponents = Buffer.concat([
payGoAttestationProofComponents.entropy,
payGoAttestationProofComponents.address,
payGoAttestationProofComponents.uuid,
]);
const verifyConstructedProof = createPayGoAttestationBuffer(
addressToVerify,
stored[0].key.keydata,
utxolib.networks.bitcoin
);

assert(addressProofMsgBuffer.equals(reconstructedProofFromComponents));
assert(verifyConstructedProof.equals(reconstructedProofFromComponents));
});
});