| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | namespace BitWasp\Bitcoin\Mnemonic\Bip39; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | use BitWasp\Bitcoin\Crypto\Hash; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | use BitWasp\Bitcoin\Crypto\Random\Random; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | use BitWasp\Bitcoin\Mnemonic\MnemonicInterface; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | use BitWasp\Buffertools\Buffer; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | use BitWasp\Buffertools\BufferInterface; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | class Bip39Mnemonic implements MnemonicInterface | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |      * @var EcAdapterInterface | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     private $ecAdapter; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |      * @var Bip39WordListInterface | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |     private $wordList; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |      * @param EcAdapterInterface $ecAdapter | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |      * @param Bip39WordListInterface $wordList | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 | 36 |  |     public function __construct(EcAdapterInterface $ecAdapter, Bip39WordListInterface $wordList) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 | 36 |  |         $this->ecAdapter = $ecAdapter; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 | 36 |  |         $this->wordList = $wordList; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 | 36 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |      * Creates a new Bip39 mnemonic string. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |      * @param int $entropySize | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |      * @return string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |      * @throws \BitWasp\Bitcoin\Exceptions\RandomBytesFailure | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |     public function create($entropySize = 512) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |         $random = new Random(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |         $entropy = $random->bytes($entropySize / 8); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |         return $this->entropyToMnemonic($entropy); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |      * @param BufferInterface $entropy | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |      * @param integer $CSlen | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |      * @return string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 | 294 |  |     private function calculateChecksum(BufferInterface $entropy, $CSlen) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 | 294 |  |         $entHash = Hash::sha256($entropy); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |         // Convert byte string to padded binary string of 0/1's. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 | 294 |  |         $hashBits = str_pad(gmp_strval($entHash->getGmp(), 2), 256, '0', STR_PAD_LEFT); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |         // Take $CSlen bits for the checksum | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 | 294 |  |         $checksumBits = substr($hashBits, 0, $CSlen); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 | 294 |  |         return $checksumBits; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |      * @param BufferInterface $entropy | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |      * @return array | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 70 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 71 | 156 |  |     public function entropyToWords(BufferInterface $entropy) | 
            
                                                                        
                            
            
                                    
            
            
                | 72 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 73 | 156 |  |         if ($entropy->getSize() === 0) { | 
            
                                                                        
                            
            
                                    
            
            
                | 74 |  |  |             throw new \InvalidArgumentException('Invalid entropy, empty'); | 
            
                                                                        
                            
            
                                    
            
            
                | 75 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 76 | 156 |  |         if ($entropy->getSize() > 1024) { | 
            
                                                                        
                            
            
                                    
            
            
                | 77 | 6 |  |             throw new \InvalidArgumentException('Invalid entropy, max 1024 bytes'); | 
            
                                                                        
                            
            
                                    
            
            
                | 78 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 79 | 150 |  |         if ($entropy->getSize() % 4 !== 0) { | 
            
                                                                        
                            
            
                                    
            
            
                | 80 | 6 |  |             throw new \InvalidArgumentException('Invalid entropy, must be multitude of 4 bytes'); | 
            
                                                                        
                            
            
                                    
            
            
                | 81 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 82 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 83 | 144 |  |         $math = $this->ecAdapter->getMath(); | 
            
                                                                        
                            
            
                                    
            
            
                | 84 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 85 | 144 |  |         $ENT = $entropy->getSize() * 8; | 
            
                                                                        
                            
            
                                    
            
            
                | 86 | 144 |  |         $CS = $ENT / 32; | 
            
                                                                        
                            
            
                                    
            
            
                | 87 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 88 | 144 |  |         $bits = gmp_strval($entropy->getGmp(), 2) . $this->calculateChecksum($entropy, $CS); | 
            
                                                                        
                            
            
                                    
            
            
                | 89 | 144 |  |         $bits = str_pad($bits, ($ENT + $CS), '0', STR_PAD_LEFT); | 
            
                                                                        
                            
            
                                    
            
            
                | 90 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 91 | 144 |  |         $result = []; | 
            
                                                                        
                            
            
                                    
            
            
                | 92 | 144 |  |         foreach (str_split($bits, 11) as $bit) { | 
            
                                                                        
                            
            
                                    
            
            
                | 93 | 144 |  |             $idx = $math->baseConvert($bit, 2, 10); | 
            
                                                                        
                            
            
                                    
            
            
                | 94 | 144 |  |             $result[] = $this->wordList->getWord($idx); | 
            
                                                                        
                            
            
                                    
            
            
                | 95 | 48 |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 96 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 97 | 144 |  |         return $result; | 
            
                                                                        
                            
            
                                    
            
            
                | 98 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |      * @param BufferInterface $entropy | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |      * @return string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 | 156 |  |     public function entropyToMnemonic(BufferInterface $entropy) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 | 156 |  |         return implode(' ', $this->entropyToWords($entropy)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |      * @param string $mnemonic | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |      * @return BufferInterface | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 | 162 |  |     public function mnemonicToEntropy($mnemonic) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 | 162 |  |         $math = $this->ecAdapter->getMath(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 | 162 |  |         $words = explode(' ', $mnemonic); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 | 162 |  |         if (count($words) % 3 !== 0) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 | 6 |  |             throw new \InvalidArgumentException('Invalid mnemonic'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 | 156 |  |         $bits = array(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 | 156 |  |         foreach ($words as $word) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 | 156 |  |             $idx = $this->wordList->getIndex($word); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 | 156 |  |             $bits[] = str_pad($math->baseConvert($idx, 10, 2), 11, '0', STR_PAD_LEFT); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 | 52 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 | 156 |  |         $bits = implode('', $bits); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |         // max entropy is 1024; (1024×8)+((1024×8)÷32) = 8448 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 | 156 |  |         if (strlen($bits) > 8448) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 | 6 |  |             throw new \InvalidArgumentException('Invalid mnemonic, too long'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 | 150 |  |         $CS = strlen($bits) / 33; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 | 150 |  |         $ENT = strlen($bits) - $CS; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 | 150 |  |         $csBits = substr($bits, -1 * $CS); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 | 150 |  |         $entBits = substr($bits, 0, -1 * $CS); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 | 150 |  |         $binary = ''; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 | 150 |  |         $bitsInChar = 8; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 | 150 |  |         for ($i = 0; $i < $ENT; $i += $bitsInChar) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |             // Extract 8 bits at a time, convert to hex, pad, and convert to binary. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 | 150 |  |             $eBits = substr($entBits, $i, $bitsInChar); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 | 150 |  |             $binary .= pack("H*", (str_pad($math->baseConvert($eBits, 2, 16), 2, '0', STR_PAD_LEFT))); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 | 50 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 | 150 |  |         $entropy = new Buffer($binary, null, $math); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 | 150 |  |         if ($csBits !== $this->calculateChecksum($entropy, $CS)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 | 6 |  |             throw new \InvalidArgumentException('Checksum does not match'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 | 144 |  |         return $entropy; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 156 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 157 |  |  |  |