import { ConsensusBCH } from '../bch/bch' ; import { isDefinedSigningSerializationType } from './signing-serialization' ; const enum PublicKey { uncompressedByteLength = 65 , uncompressedHeaderByte = 0x04 , compressedByteLength = 33 , compressedHeaderByteEven = 0x02 , compressedHeaderByteOdd = 0x03 } export const isValidUncompressedPublicKeyEncoding = ( publicKey ) => publicKey . length === PublicKey . uncompressedByteLength && publicKey [ 0 ] === PublicKey . uncompressedHeaderByte ; export const isValidCompressedPublicKeyEncoding = ( publicKey ) => publicKey . length === PublicKey . compressedByteLength && ( publicKey [ 0 ] === PublicKey . compressedHeaderByteEven || publicKey [ 0 ] === PublicKey . compressedHeaderByteOdd ) ; export const isValidPublicKeyEncoding = ( publicKey ) => isValidCompressedPublicKeyEncoding ( publicKey ) || isValidUncompressedPublicKeyEncoding ( publicKey ) ; const enum ASN1 { sequenceTagType = 0x30 , integerTagType = 0x02 } const enum DER { minimumLength = 8 , maximumLength = 72 , sequenceTagIndex = 0 , sequenceLengthIndex = 1 , rTagIndex = 2 , rLengthIndex = 3 , rValueIndex = 4 , sequenceTagByte = 1 , sequenceLengthByte = 1 , integerTagByte = 1 , integerLengthByte = 1 , sequenceMetadataBytes = sequenceTagByte + sequenceLengthByte , integerMetadataBytes = integerTagByte + integerLengthByte , minimumSValueBytes = 1 , minimumNonRValueBytes = sequenceMetadataBytes + integerMetadataBytes + integerMetadataBytes + minimumSValueBytes } const enum Mask { negative = 0x80 } const isNegative = ( value ) => ( value & Mask . negative ) !== 0 ; const hasUnnecessaryPadding = ( length , firstByte , secondByte ) => length > 1 && firstByte === 0 && ! isNegative ( secondByte ) ; const isValidInteger = ( signature , tagIndex , length , valueIndex ) => signature [ tagIndex ] === ASN1 . integerTagType && length !== 0 && ! isNegative ( signature [ valueIndex ] ) && ! hasUnnecessaryPadding ( length , signature [ valueIndex ] , signature [ valueIndex + 1 ] ) ; remarks privateRemarks export const isValidSignatureEncodingDER = ( signature ) => { const correctLengthRange = signature . length > DER . minimumLength && signature . length < DER . maximumLength ; const correctSequenceTagType = signature [ DER . sequenceTagIndex ] === ASN1 . sequenceTagType ; const correctSequenceLength = signature [ DER . sequenceLengthIndex ] === signature . length - DER . sequenceMetadataBytes ; const rLength = signature [ DER . rLengthIndex ] as number | undefined ; if ( rLength === undefined ) { return false ; } const consistentRLength = rLength <= signature . length - DER . minimumNonRValueBytes ; const rIsValid = isValidInteger ( signature , DER . rTagIndex , rLength , DER . rValueIndex ) ; const sTagIndex = DER . rValueIndex + rLength ; const sLengthIndex = sTagIndex + 1 ; const sLength = signature [ sLengthIndex ] as number | undefined ; if ( sLength === undefined ) { return false ; } const sValueIndex = sLengthIndex + 1 ; const consistentSLength = sValueIndex + sLength === signature . length ; const sIsValid = isValidInteger ( signature , sTagIndex , sLength , sValueIndex ) ; return ( correctLengthRange && correctSequenceTagType && correctSequenceLength && consistentRLength && rIsValid && consistentSLength && sIsValid ) ; } ; param transactionSignature export const isValidSignatureEncodingBCHTransaction = ( transactionSignature ) => transactionSignature . length === 0 || transactionSignature . length === ConsensusBCH . schnorrSignatureLength + 1 || ( isDefinedSigningSerializationType ( transactionSignature [ transactionSignature . length - 1 ] ) && isValidSignatureEncodingDER ( transactionSignature . slice ( 0 , transactionSignature . length - 1 ) ) ) ; param signature export const decodeBitcoinSignature = ( encodedSignature ) => ( { signature : encodedSignature . slice ( 0 , encodedSignature . length - 1 ) , signingSerializationType : new Uint8Array ( [ encodedSignature [ encodedSignature . length - 1 ] , ] ) , } ) ;