diff --git a/cryptofuzz/Wallet.py b/cryptofuzz/Wallet.py new file mode 100644 index 0000000..b8a6460 --- /dev/null +++ b/cryptofuzz/Wallet.py @@ -0,0 +1,91 @@ +import os, random +import utils + + +def getPrivateKey(): return utils.generate_private_key() + + +def getByte(size: int = 32) -> bytes: return os.urandom(size) + + +def getMnemonic(size: int) -> str: + if size: + return utils.generate_mnemonic(size) + else: + return utils.generate_mnemonic(size=12) + + +def getRootKey(): return utils.generate_xprv() + + +def getBinary(): + bin_data = [''.join(random.choices('01', k=8)) for _ in range(32)] + return ''.join(bin_data) + + +def getEntropy(size: int = 256) -> bytes: + return utils.generate_entropy(size) + + +def getChecksum(data: bytes) -> bytes: + return utils.SHA256(data).digest()[:4] + + +def PrivateKey_To_Addr(private_key: str, compress: bool = False) -> str: + seed = utils.hex_to_bytes(private_key) + priv, pub = utils.byte_to_keys(seed) + if compress: + return utils.pub_to_addr(pub, True) + else: + return utils.pub_to_addr(pub, False) + + +def PrivateKey_To_WIF(private_key: str, compress: bool = False) -> str: + seed = utils.hex_to_bytes(private_key) + priv, pub = utils.byte_to_keys(seed) + if compress: + return utils.byte_to_wif(priv, True) + else: + return utils.byte_to_wif(priv, False) + + +def Mnemonic_To_Addr(mnemonic: str, password: str = "", compress: bool = False) -> str: + seed = utils.mne_to_seed(mnemonic, password) + priv, pub = utils.byte_to_keys(seed) + if compress: + return utils.pub_to_addr(pub, True) + else: + return utils.pub_to_addr(pub, False) + + +def Bytes_To_PrivateKey(data: bytes) -> str: return utils.byte_to_hex(data) + + +def Bytes_To_WIF(data: bytes, compress: bool = False) -> str: + if compress: + return utils.byte_to_wif(data, True) + else: + return utils.byte_to_wif(data, False) + + +def Bytes_To_Mnemonic(data: bytes) -> str: return utils.byte_to_mne(data) + + +def Bytes_To_Dec(data: bytes) -> int: return int.from_bytes(data, byteorder='big') + + +def Bytes_To_Hex(data: bytes) -> str: return data.hex() + + +def Bytes_To_Addr(data: bytes, compress: bool = False) -> str: + pvk, pub = utils.byte_to_keys(data) + if compress: + return utils.pub_to_addr(pub, True) + else: + return utils.pub_to_addr(pub, False) + + +def Bytes_To_PublicKey(data: bytes) -> str: + _, pub = utils.byte_to_keys(data) + return pub.hex() + diff --git a/cryptofuzz/__init__.py b/cryptofuzz/__init__.py index 1d29194..170fef1 100644 --- a/cryptofuzz/__init__.py +++ b/cryptofuzz/__init__.py @@ -15,5 +15,7 @@ "__description__", "assest", "bs58", - "utils" -] + "utils", + "hd", + "Wallet" +] \ No newline at end of file diff --git a/cryptofuzz/assest.py b/cryptofuzz/assest.py index 59a9ffe..85cb24c 100644 --- a/cryptofuzz/assest.py +++ b/cryptofuzz/assest.py @@ -3,8 +3,13 @@ BITCOIN_ALPHABET = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' RIPPLE_ALPHABET = b'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz' BIP39 = "AbandonAbilityAbleAboutAboveAbsentAbsorbAbstractAbsurdAbuseAccessAccidentAccountAccuseAchieveAcidAcousticAcquireAcrossActActionActorActressActualAdaptAddAddictAddressAdjustAdmitAdultAdvanceAdviceAerobicAffairAffordAfraidAgainAgeAgentAgreeAheadAimAirAirportAisleAlarmAlbumAlcoholAlertAlienAllAlleyAllowAlmostAloneAlphaAlreadyAlsoAlterAlwaysAmateurAmazingAmongAmountAmusedAnalystAnchorAncientAngerAngleAngryAnimalAnkleAnnounceAnnualAnotherAnswerAntennaAntiqueAnxietyAnyApartApologyAppearAppleApproveAprilArchArcticAreaArenaArgueArmArmedArmorArmyAroundArrangeArrestArriveArrowArtArtefactArtistArtworkAskAspectAssaultAssetAssistAssumeAsthmaAthleteAtomAttackAttendAttitudeAttractAuctionAuditAugustAuntAuthorAutoAutumnAverageAvocadoAvoidAwakeAwareAwayAwesomeAwfulAwkwardAxisBabyBachelorBaconBadgeBagBalanceBalconyBallBambooBananaBannerBarBarelyBargainBarrelBaseBasicBasketBattleBeachBeanBeautyBecauseBecomeBeefBeforeBeginBehaveBehindBelieveBelowBeltBenchBenefitBestBetrayBetterBetweenBeyondBicycleBidBikeBindBiologyBirdBirthBitterBlackBladeBlameBlanketBlastBleakBlessBlindBloodBlossomBlouseBlueBlurBlushBoardBoatBodyBoilBombBoneBonusBookBoostBorderBoringBorrowBossBottomBounceBoxBoyBracketBrainBrandBrassBraveBreadBreezeBrickBridgeBriefBrightBringBriskBroccoliBrokenBronzeBroomBrotherBrownBrushBubbleBuddyBudgetBuffaloBuildBulbBulkBulletBundleBunkerBurdenBurgerBurstBusBusinessBusyButterBuyerBuzzCabbageCabinCableCactusCageCakeCallCalmCameraCampCanCanalCancelCandyCannonCanoeCanvasCanyonCapableCapitalCaptainCarCarbonCardCargoCarpetCarryCartCaseCashCasinoCastleCasualCatCatalogCatchCategoryCattleCaughtCauseCautionCaveCeilingCeleryCementCensusCenturyCerealCertainChairChalkChampionChangeChaosChapterChargeChaseChatCheapCheckCheeseChefCherryChestChickenChiefChildChimneyChoiceChooseChronicChuckleChunkChurnCigarCinnamonCircleCitizenCityCivilClaimClapClarifyClawClayCleanClerkCleverClickClientCliffClimbClinicClipClockClogCloseClothCloudClownClubClumpClusterClutchCoachCoastCoconutCodeCoffeeCoilCoinCollectColorColumnCombineComeComfortComicCommonCompanyConcertConductConfirmCongressConnectConsiderControlConvinceCookCoolCopperCopyCoralCoreCornCorrectCostCottonCouchCountryCoupleCourseCousinCoverCoyoteCrackCradleCraftCramCraneCrashCraterCrawlCrazyCreamCreditCreekCrewCricketCrimeCrispCriticCropCrossCrouchCrowdCrucialCruelCruiseCrumbleCrunchCrushCryCrystalCubeCultureCupCupboardCuriousCurrentCurtainCurveCushionCustomCuteCycleDadDamageDampDanceDangerDaringDashDaughterDawnDayDealDebateDebrisDecadeDecemberDecideDeclineDecorateDecreaseDeerDefenseDefineDefyDegreeDelayDeliverDemandDemiseDenialDentistDenyDepartDependDepositDepthDeputyDeriveDescribeDesertDesignDeskDespairDestroyDetailDetectDevelopDeviceDevoteDiagramDialDiamondDiaryDiceDieselDietDifferDigitalDignityDilemmaDinnerDinosaurDirectDirtDisagreeDiscoverDiseaseDishDismissDisorderDisplayDistanceDivertDivideDivorceDizzyDoctorDocumentDogDollDolphinDomainDonateDonkeyDonorDoorDoseDoubleDoveDraftDragonDramaDrasticDrawDreamDressDriftDrillDrinkDripDriveDropDrumDryDuckDumbDuneDuringDustDutchDutyDwarfDynamicEagerEagleEarlyEarnEarthEasilyEastEasyEchoEcologyEconomyEdgeEditEducateEffortEggEightEitherElbowElderElectricElegantElementElephantElevatorEliteElseEmbarkEmbodyEmbraceEmergeEmotionEmployEmpowerEmptyEnableEnactEndEndlessEndorseEnemyEnergyEnforceEngageEngineEnhanceEnjoyEnlistEnoughEnrichEnrollEnsureEnterEntireEntryEnvelopeEpisodeEqualEquipEraEraseErodeErosionErrorEruptEscapeEssayEssenceEstateEternalEthicsEvidenceEvilEvokeEvolveExactExampleExcessExchangeExciteExcludeExcuseExecuteExerciseExhaustExhibitExileExistExitExoticExpandExpectExpireExplainExposeExpressExtendExtraEyeEyebrowFabricFaceFacultyFadeFaintFaithFallFalseFameFamilyFamousFanFancyFantasyFarmFashionFatFatalFatherFatigueFaultFavoriteFeatureFebruaryFederalFeeFeedFeelFemaleFenceFestivalFetchFeverFewFiberFictionFieldFigureFileFilmFilterFinalFindFineFingerFinishFireFirmFirstFiscalFishFitFitnessFixFlagFlameFlashFlatFlavorFleeFlightFlipFloatFlockFloorFlowerFluidFlushFlyFoamFocusFogFoilFoldFollowFoodFootForceForestForgetForkFortuneForumForwardFossilFosterFoundFoxFragileFrameFrequentFreshFriendFringeFrogFrontFrostFrownFrozenFruitFuelFunFunnyFurnaceFuryFutureGadgetGainGalaxyGalleryGameGapGarageGarbageGardenGarlicGarmentGasGaspGateGatherGaugeGazeGeneralGeniusGenreGentleGenuineGestureGhostGiantGiftGiggleGingerGiraffeGirlGiveGladGlanceGlareGlassGlideGlimpseGlobeGloomGloryGloveGlowGlueGoatGoddessGoldGoodGooseGorillaGospelGossipGovernGownGrabGraceGrainGrantGrapeGrassGravityGreatGreenGridGriefGritGroceryGroupGrowGruntGuardGuessGuideGuiltGuitarGunGymHabitHairHalfHammerHamsterHandHappyHarborHardHarshHarvestHatHaveHawkHazardHeadHealthHeartHeavyHedgehogHeightHelloHelmetHelpHenHeroHiddenHighHillHintHipHireHistoryHobbyHockeyHoldHoleHolidayHollowHomeHoneyHoodHopeHornHorrorHorseHospitalHostHotelHourHoverHubHugeHumanHumbleHumorHundredHungryHuntHurdleHurryHurtHusbandHybridIceIconIdeaIdentifyIdleIgnoreIllIllegalIllnessImageImitateImmenseImmuneImpactImposeImproveImpulseInchIncludeIncomeIncreaseIndexIndicateIndoorIndustryInfantInflictInformInhaleInheritInitialInjectInjuryInmateInnerInnocentInputInquiryInsaneInsectInsideInspireInstallIntactInterestIntoInvestInviteInvolveIronIslandIsolateIssueItemIvoryJacketJaguarJarJazzJealousJeansJellyJewelJobJoinJokeJourneyJoyJudgeJuiceJumpJungleJuniorJunkJustKangarooKeenKeepKetchupKeyKickKidKidneyKindKingdomKissKitKitchenKiteKittenKiwiKneeKnifeKnockKnowLabLabelLaborLadderLadyLakeLampLanguageLaptopLargeLaterLatinLaughLaundryLavaLawLawnLawsuitLayerLazyLeaderLeafLearnLeaveLectureLeftLegLegalLegendLeisureLemonLendLengthLensLeopardLessonLetterLevelLiarLibertyLibraryLicenseLifeLiftLightLikeLimbLimitLinkLionLiquidListLittleLiveLizardLoadLoanLobsterLocalLockLogicLonelyLongLoopLotteryLoudLoungeLoveLoyalLuckyLuggageLumberLunarLunchLuxuryLyricsMachineMadMagicMagnetMaidMailMainMajorMakeMammalManManageMandateMangoMansionManualMapleMarbleMarchMarginMarineMarketMarriageMaskMassMasterMatchMaterialMathMatrixMatterMaximumMazeMeadowMeanMeasureMeatMechanicMedalMediaMelodyMeltMemberMemoryMentionMenuMercyMergeMeritMerryMeshMessageMetalMethodMiddleMidnightMilkMillionMimicMindMinimumMinorMinuteMiracleMirrorMiseryMissMistakeMixMixedMixtureMobileModelModifyMomMomentMonitorMonkeyMonsterMonthMoonMoralMoreMorningMosquitoMotherMotionMotorMountainMouseMoveMovieMuchMuffinMuleMultiplyMuscleMuseumMushroomMusicMustMutualMyselfMysteryMythNaiveNameNapkinNarrowNastyNationNatureNearNeckNeedNegativeNeglectNeitherNephewNerveNestNetNetworkNeutralNeverNewsNextNiceNightNobleNoiseNomineeNoodleNormalNorthNoseNotableNoteNothingNoticeNovelNowNuclearNumberNurseNutOakObeyObjectObligeObscureObserveObtainObviousOccurOceanOctoberOdorOffOfferOfficeOftenOilOkayOldOliveOlympicOmitOnceOneOnionOnlineOnlyOpenOperaOpinionOpposeOptionOrangeOrbitOrchardOrderOrdinaryOrganOrientOriginalOrphanOstrichOtherOutdoorOuterOutputOutsideOvalOvenOverOwnOwnerOxygenOysterOzonePactPaddlePagePairPalacePalmPandaPanelPanicPantherPaperParadeParentParkParrotPartyPassPatchPathPatientPatrolPatternPausePavePaymentPeacePeanutPearPeasantPelicanPenPenaltyPencilPeoplePepperPerfectPermitPersonPetPhonePhotoPhrasePhysicalPianoPicnicPicturePiecePigPigeonPillPilotPinkPioneerPipePistolPitchPizzaPlacePlanetPlasticPlatePlayPleasePledgePluckPlugPlungePoemPoetPointPolarPolePolicePondPonyPoolPopularPortionPositionPossiblePostPotatoPotteryPovertyPowderPowerPracticePraisePredictPreferPreparePresentPrettyPreventPricePridePrimaryPrintPriorityPrisonPrivatePrizeProblemProcessProduceProfitProgramProjectPromoteProofPropertyProsperProtectProudProvidePublicPuddingPullPulpPulsePumpkinPunchPupilPuppyPurchasePurityPurposePursePushPutPuzzlePyramidQualityQuantumQuarterQuestionQuickQuitQuizQuoteRabbitRaccoonRaceRackRadarRadioRailRainRaiseRallyRampRanchRandomRangeRapidRareRateRatherRavenRawRazorReadyRealReasonRebelRebuildRecallReceiveRecipeRecordRecycleReduceReflectReformRefuseRegionRegretRegularRejectRelaxReleaseReliefRelyRemainRememberRemindRemoveRenderRenewRentReopenRepairRepeatReplaceReportRequireRescueResembleResistResourceResponseResultRetireRetreatReturnReunionRevealReviewRewardRhythmRibRibbonRiceRichRideRidgeRifleRightRigidRingRiotRippleRiskRitualRivalRiverRoadRoastRobotRobustRocketRomanceRoofRookieRoomRoseRotateRoughRoundRouteRoyalRubberRudeRugRuleRunRunwayRuralSadSaddleSadnessSafeSailSaladSalmonSalonSaltSaluteSameSampleSandSatisfySatoshiSauceSausageSaveSayScaleScanScareScatterSceneSchemeSchoolScienceScissorsScorpionScoutScrapScreenScriptScrubSeaSearchSeasonSeatSecondSecretSectionSecuritySeedSeekSegmentSelectSellSeminarSeniorSenseSentenceSeriesServiceSessionSettleSetupSevenShadowShaftShallowShareShedShellSheriffShieldShiftShineShipShiverShockShoeShootShopShortShoulderShoveShrimpShrugShuffleShySiblingSickSideSiegeSightSignSilentSilkSillySilverSimilarSimpleSinceSingSirenSisterSituateSixSizeSkateSketchSkiSkillSkinSkirtSkullSlabSlamSleepSlenderSliceSlideSlightSlimSloganSlotSlowSlushSmallSmartSmileSmokeSmoothSnackSnakeSnapSniffSnowSoapSoccerSocialSockSodaSoftSolarSoldierSolidSolutionSolveSomeoneSongSoonSorrySortSoulSoundSoupSourceSouthSpaceSpareSpatialSpawnSpeakSpecialSpeedSpellSpendSphereSpiceSpiderSpikeSpinSpiritSplitSpoilSponsorSpoonSportSpotSpraySpreadSpringSpySquareSqueezeSquirrelStableStadiumStaffStageStairsStampStandStartStateStaySteakSteelStemStepStereoStickStillStingStockStomachStoneStoolStoryStoveStrategyStreetStrikeStrongStruggleStudentStuffStumbleStyleSubjectSubmitSubwaySuccessSuchSuddenSufferSugarSuggestSuitSummerSunSunnySunsetSuperSupplySupremeSureSurfaceSurgeSurpriseSurroundSurveySuspectSustainSwallowSwampSwapSwarmSwearSweetSwiftSwimSwingSwitchSwordSymbolSymptomSyrupSystemTableTackleTagTailTalentTalkTankTapeTargetTaskTasteTattooTaxiTeachTeamTellTenTenantTennisTentTermTestTextThankThatThemeThenTheoryThereTheyThingThisThoughtThreeThriveThrowThumbThunderTicketTideTigerTiltTimberTimeTinyTipTiredTissueTitleToastTobaccoTodayToddlerToeTogetherToiletTokenTomatoTomorrowToneTongueTonightToolToothTopTopicToppleTorchTornadoTortoiseTossTotalTouristTowardTowerTownToyTrackTradeTrafficTragicTrainTransferTrapTrashTravelTrayTreatTreeTrendTrialTribeTrickTriggerTrimTripTrophyTroubleTruckTrueTrulyTrumpetTrustTruthTryTubeTuitionTumbleTunaTunnelTurkeyTurnTurtleTwelveTwentyTwiceTwinTwistTwoTypeTypicalUglyUmbrellaUnableUnawareUncleUncoverUnderUndoUnfairUnfoldUnhappyUniformUniqueUnitUniverseUnknownUnlockUntilUnusualUnveilUpdateUpgradeUpholdUponUpperUpsetUrbanUrgeUsageUseUsedUsefulUselessUsualUtilityVacantVacuumVagueValidValleyValveVanVanishVaporVariousVastVaultVehicleVelvetVendorVentureVenueVerbVerifyVersionVeryVesselVeteranViableVibrantViciousVictoryVideoViewVillageVintageViolinVirtualVirusVisaVisitVisualVitalVividVocalVoiceVoidVolcanoVolumeVoteVoyageWageWagonWaitWalkWallWalnutWantWarfareWarmWarriorWashWaspWasteWaterWaveWayWealthWeaponWearWeaselWeatherWebWeddingWeekendWeirdWelcomeWestWetWhaleWhatWheatWheelWhenWhereWhipWhisperWideWidthWifeWildWillWinWindowWineWingWinkWinnerWinterWireWisdomWiseWishWitnessWolfWomanWonderWoodWoolWordWorkWorldWorryWorthWrapWreckWrestleWristWriteWrongYardYearYellowYouYoungYouthZebraZeroZoneZoo" +BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' # main MAIN_PREFIX = b'\x80' MAIN_SUFFIX = b'\x01' +COMPRESSED_PREFIX = b'\x03' +COMPRESSED_PREFIX2 = b'\x02' +UNCOMPRESSED_PREFIX = b'\x04' MAIN_DIGEST_RMD160 = b"\x00" +MAX_PRIVATE_KEY = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140 diff --git a/cryptofuzz/bs58.py b/cryptofuzz/bs58.py index fb9c788..fb6404f 100644 --- a/cryptofuzz/bs58.py +++ b/cryptofuzz/bs58.py @@ -3,7 +3,8 @@ from typing import Mapping, Union from assest import ( BITCOIN_ALPHABET as ALPHABET, - RIPPLE_ALPHABET as XRP_ALPHABET + RIPPLE_ALPHABET as XRP_ALPHABET, + BASE58_ALPHABET ) @@ -134,3 +135,17 @@ def b58decode_check( raise ValueError("Invalid checksum") return result + + +def base58_encode(num): + num = int(num, 16) + encoded = '' + while num: + num, remainder = divmod(num, 58) + encoded = BASE58_ALPHABET[remainder] + encoded + return encoded + +def base58_check_encode(payload, prefix=0x00): + payload = bytes([prefix]) + payload + checksum = sha256(sha256(payload).digest()).digest()[:4] + return base58_encode(payload.hex() + checksum.hex()) \ No newline at end of file diff --git a/cryptofuzz/hd.py b/cryptofuzz/hd.py new file mode 100644 index 0000000..da5c3c6 --- /dev/null +++ b/cryptofuzz/hd.py @@ -0,0 +1,103 @@ +import sys + +from hdwallet import HDWallet +from hdwallet.symbols import BTC, ETH, LTC, TRX, DASH, DGB, BTG, DOGE, RVN, QTUM + + +def hex2eth(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=ETH) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2trx(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=TRX) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2ltc(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=LTC) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2dash(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=DASH) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2btg(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=BTG) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2dgb(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=DGB) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2doge(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=DOGE) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2rvn(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=RVN) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2qtum(pvk: str) -> str: + hd: HDWallet = HDWallet(symbol=QTUM) + hd.from_private_key(private_key=pvk) + return hd.p2pkh_address() + + +def hex2btc(pvk: str, type: str) -> str: + """ + Convert a given hexadecimal private key to a Bitcoin address of the specified type. + + Args: + pvk (str): The hexadecimal private key. + type (str): The type of Bitcoin address to generate. + Possible values are "p2pkh", "p2sh", "p2wpkh", "p2wsh", "p2wpkh-p2sh", "p2wsh-p2sh". + + Returns: + str: The Bitcoin address corresponding to the private key and address type. + + Raises: + None + + Example: + >>> hex2btc("0123456789abcdef", "p2pkh") + "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa" + + >>> hex2btc("0123456789abcdef", "p2sh") + "3FZbgi29cpjq2GjdwV8eyHuJJnkLtktZc5" + + Note: + Make sure that the private key is a valid hexadecimal string. + """ + hd: HDWallet = HDWallet(symbol=BTC) + hd.from_private_key(private_key=pvk) + if type == "p2pkh": + return hd.p2pkh_address() + elif type == "p2sh": + return hd.p2sh_address() + elif type == "p2wpkh": + return hd.p2wpkh_address() + elif type == "p2wsh": + return hd.p2wsh_address() + elif type == "p2wpkh-p2sh": + return hd.p2wpkh_in_p2sh_address() + elif type == "p2wsh-p2sh": + return hd.p2wsh_in_p2sh_address() + else: + err = f"Invalid address type: {type} not supported. Supported types are: p2pkh | p2sh | p2wpkh | p2wsh | p2wpkh-p2sh | p2wsh-p2sh" + sys.stdout.write(err) + diff --git a/cryptofuzz/tst.py b/cryptofuzz/tst.py new file mode 100644 index 0000000..76b129a --- /dev/null +++ b/cryptofuzz/tst.py @@ -0,0 +1,20 @@ +from utils import * + +import os + + +pvk = os.urandom(32).hex() + +seed = hex_to_bytes(pvk) + +pub = bytes_to_pub(seed) + +caddr = pub_to_addr(pub, True) +uaddr = pub_to_addr(pub, False) + +print(f"Private Key: {pvk}") +print(f"Seed: {seed}") +print(f"Public Key: {pub}") +print(f"Compressed Address: {caddr}") +print(f"Uncompressed Address: {uaddr}") + diff --git a/cryptofuzz/tst2.py b/cryptofuzz/tst2.py new file mode 100644 index 0000000..51c375a --- /dev/null +++ b/cryptofuzz/tst2.py @@ -0,0 +1,67 @@ +import os +import binascii +import ecdsa +import hashlib +import base58 + + +def generate_xprv(): + seed = os.urandom(64) + return "xprv" + binascii.hexlify(seed).decode('utf-8') + + +def xprv_to_private_key(xprv): + return binascii.unhexlify(xprv[4:])[:32] # Take the first 32 bytes as the private key + + +def double_sha256(data): + return hashlib.sha256(hashlib.sha256(data).digest()).digest() + + +def ripemd160(data): + h = hashlib.new('ripemd160') + h.update(data) + return h.digest() + + +def private_key_to_public_key(private_key): + sk = ecdsa.SigningKey.from_string(private_key, curve=ecdsa.SECP256k1) + return sk.get_verifying_key() + + +def public_key_to_address(pubkey, compressed=True): + # Get x and y coordinates from the public key + x = pubkey.pubkey.point.x() + y = pubkey.pubkey.point.y() + + if compressed: + if y & 1: + pubkey_bytes = b'\x03' + x.to_bytes(32, 'big') + else: + pubkey_bytes = b'\x02' + x.to_bytes(32, 'big') + else: + pubkey_bytes = b'\x04' + x.to_bytes(32, 'big') + y.to_bytes(32, 'big') + + hashed_pubkey = ripemd160(double_sha256(pubkey_bytes)) + address_bytes = b'\x00' + hashed_pubkey + checksum = double_sha256(address_bytes)[:4] + + return base58.b58encode(address_bytes + checksum).decode('utf-8') + + +def main(): + xprv = generate_xprv() + print("XPRV:", xprv) + + private_key = xprv_to_private_key(xprv) + public_key = private_key_to_public_key(private_key) + + compressed_address = public_key_to_address(public_key, compressed=True) + uncompressed_address = public_key_to_address(public_key, compressed=False) + + print("Compressed Address:", compressed_address) + print("Uncompressed Address:", uncompressed_address) + + +if __name__ == "__main__": + main() diff --git a/cryptofuzz/utils.py b/cryptofuzz/utils.py index a457b95..800545e 100644 --- a/cryptofuzz/utils.py +++ b/cryptofuzz/utils.py @@ -1,41 +1,107 @@ import binascii -import os, re -import hashlib, pbkdf2, hmac +import os, re, hashlib import hmac import random -from hashlib import sha256 as SHA256, sha512 as SHA512, new as NEW import ecdsa -from bs58 import b58encode, b58encode_check, b58decode_check, b58decode +from bs58 import b58encode, b58encode_check, b58decode_check, b58decode, base58_check_encode, base58_encode from mnemonic import Mnemonic from assest import ( MAIN_DIGEST_RMD160, + MAX_PRIVATE_KEY, MAIN_PREFIX, MAIN_SUFFIX, + COMPRESSED_PREFIX, + COMPRESSED_PREFIX2, + UNCOMPRESSED_PREFIX, BIP39 ) +def checkValid(key: int) -> bool: + """ + Check if the given key is valid. + + Args: + key (int): The key to be checked. + + Returns: + bool: True if the key is valid, False otherwise. + + Raises: + ValueError: If the key is not within the valid range. + """ + if 0 < key < MAX_PRIVATE_KEY: + return True + else: + raise ValueError(f"Secret Scalar Must be greater than 0 and less than {MAX_PRIVATE_KEY}.") + + +def generate_private_key(): + randkey = "".join(random.choice("0123456789abcdef") for _ in range(64)) + if checkValid(int(randkey, 16)): + return randkey + else: + return generate_private_key() + + +def double_sha256(data): return hashlib.sha256(hashlib.sha256(data).digest()).digest() + + +def generate_xprv(): + seed = os.urandom(32) + return "xprv" + binascii.hexlify(seed).decode('utf-8') + + def generate_entropy(entropy_bits=256): entropy = os.urandom(entropy_bits // 8) - checksum = SHA256(entropy).digest()[0] + checksum = hashlib.sha256(entropy).digest()[0] entropy_with_checksum = entropy + bytes([checksum]) return entropy_with_checksum +def generate_mnemonic(size: int) -> str: + characters = re.findall('[A-Z][a-z]+', BIP39) + return " ".join(random.choices(characters, k=size)).lower() + + def mne_to_seed(mnemonic, password=""): salt = ("mnemonic" + password).encode('utf-8') seed = hashlib.pbkdf2_hmac('sha512', mnemonic.encode('utf-8'), salt, 2048) return seed[:64] -def generate_keypair(seed): - sk = ecdsa.SigningKey.from_string(seed[:32], curve=ecdsa.SECP256k1) +def hex_to_bytes(hexed): return bytes.fromhex(hexed) + + +def byte_to_hex(seed): + privatekey_int = int.from_bytes(hashlib.sha256(seed).digest(), byteorder='big') + checkValid(privatekey_int) + return privatekey_int.to_bytes(32, byteorder='big') + + +def bytes_to_pub(seed): + sk = ecdsa.SigningKey.from_string(seed, curve=ecdsa.SECP256k1) + return sk.get_verifying_key() + + +def byte_to_keys(seed_bytes: bytes): + """ + convert bytes seed to private key bytes ans public key bytes. + + >>> private, public = byte_to_keys(seed_bytes) + >>> privatekey = private.to_string() + >>> publickey = public.to_string() + + :param: seed_bytes + :return: signing_key, verifying_key. + """ + sk = ecdsa.SigningKey.from_string(seed_bytes[:32], curve=ecdsa.SECP256k1) vk = sk.get_verifying_key() return sk, vk -def pub_to_addr(pubkey, compressed=True): - if compressed: +def pub_to_addr(pubkey, compress=True): + if compress: if pubkey.to_string()[63] % 2 == 0: compressed_pub = b"\x02" + pubkey.to_string()[:32] else: @@ -43,24 +109,37 @@ def pub_to_addr(pubkey, compressed=True): else: compressed_pub = b"\x04" + pubkey.to_string() - ripemd160 = NEW('ripemd160') - ripemd160.update(SHA256(compressed_pub).digest()) + ripemd160 = hashlib.new('ripemd160') + ripemd160.update(hashlib.sha256(compressed_pub).digest()) raw_address = MAIN_DIGEST_RMD160 + ripemd160.digest() - address = b58encode(raw_address + SHA256(SHA256(raw_address).digest()).digest()[:4]) + address = b58encode(raw_address + double_sha256(raw_address)[:4]) return address -def byte2Mne(byte: bytes): return Mnemonic("english").to_mnemonic(byte[:32]) + +def pub_to_bytes(pubkey, compress=True): + if compress: + prefix = (b'\x03' if pubkey.pubkey.point.y() & 1 else b'\x02') + return prefix + pubkey.pubkey.point.x().to_bytes(32, 'big') + else: + return b'\x04' + pubkey.pubkey.point.x().to_bytes(32, 'big') + pubkey.pubkey.point.y().to_bytes(32, 'big') + + +def pub_to_hex(pubkey, compress=True): + return pub_to_bytes(pubkey, compress).hex() -def bytes2Wif(private_key, compress=True): +def byte_to_mne(byte: bytes): return Mnemonic("english").to_mnemonic(byte[:32]) + + +def byte_to_wif(private_key, compress=True): PREFIX = MAIN_PREFIX if compress: EXTENDED_KEY = PREFIX + private_key + MAIN_SUFFIX else: EXTENDED_KEY = PREFIX + private_key - FIRST_SHA256 = SHA256(EXTENDED_KEY).digest() - DOUBLE_SHA256 = SHA256(FIRST_SHA256).digest() + # FIRST_SHA256 = SHA256(EXTENDED_KEY).digest() + DOUBLE_SHA256 = double_sha256(EXTENDED_KEY) CHECKSUM = DOUBLE_SHA256[:4] WIF = b58encode(EXTENDED_KEY + CHECKSUM) @@ -68,18 +147,23 @@ def bytes2Wif(private_key, compress=True): return WIF.decode('utf-8') -def generate_mnemonic(size: int) -> str: - characters = re.findall('[A-Z][a-z]+', BIP39) - return " ".join(random.choices(characters, k=size)).lower() - - -word = generate_mnemonic(12) +def pass_To_addr(passphrase, compressed=False): + priv_key_hex = hashlib.sha256(passphrase.encode()).hexdigest() + sk = ecdsa.SigningKey.from_string(bytes.fromhex(priv_key_hex), curve=ecdsa.SECP256k1) + vk = sk.verifying_key + if compressed: + if vk.pubkey.point.y() & 1: + pub_key = COMPRESSED_PREFIX + vk.to_string()[:32] + else: + pub_key = COMPRESSED_PREFIX2 + vk.to_string()[:32] + else: + pub_key = UNCOMPRESSED_PREFIX + vk.to_string() + sha = hashlib.sha256(pub_key).digest() + ripemd160 = hashlib.new('ripemd160') + ripemd160.update(sha) -seed = mne_to_seed(word) + address = base58_check_encode(ripemd160.digest()) + return "1" + address -private, public = generate_keypair(seed) -caddr = pub_to_addr(public, True) -uaddr = pub_to_addr(public, False) -print(word) -print(f"compress: {caddr}\nUncompress: {uaddr}\n{private.to_string()}") +def xprv_to_bytes(xprv): return binascii.unhexlify(xprv[4:])[:32]