티스토리 뷰

니모닉이란?
http://wiki.hash.kr/index.php/%EB%8B%88%EB%AA%A8%EB%8B%89

 

니모닉 - 해시넷

니모닉(Mnemonic)이란 지갑을 복구하기 위한 12개의 단어이다. 개인 키가 너무 복잡한 단어들로 구성되어 있기 때문에, 이를 쉽게 입력할 수 있도록 갖춰진 형식이다. 니모닉의 어원은 그리스 신화

wiki.hash.kr

한줄로 요약하자면
'기억하기 어려운 개인키를 생성하기 위한 값을 기억하기 비교적 쉬운 일상적인 단어로 바꿔서 보관하자' 정도로 말 할 수 있을 것 같다.

위의 페이지에서 적혀있는것을 보면 니모닉을 만들기 위한 순서와 구조를 확인 할 수 있다.

구현 순서:
1. 암호학적으로 랜덤한 128~256 bits의 시퀀스 S를 만든다.
2. S의 SHA-256 해시값 중에서 앞(왼쪽)에서 S의 길이 / 32비트만큼을 체크섬으로 만든다.
3. 2번에서 만든 체크섬을 S의 끝에 추가한다.
4. 3번에서 만든 시퀀스와 체크섬의 연결을 11 bits 단위로 자른다.
5. 각 각의 11비트를 2048(2^11)개의 미리 정의된 단어로 치환한다.
6. 단어 시퀀스로부터 순서를 유지하면서 니모닉 코드를 생성한다.


구현순서 및 이미지 출처: http://wiki.hash.kr/index.php/%EB%8B%88%EB%AA%A8%EB%8B%89



1. 암호학적으로 랜덤한 128~256 bits의 시퀀스 S를 만든다.

func randomBytes(length: Int) -> Data? { // 1. 랜덤값 생성
    for _ in 0...1024 {
        var data = Data(repeating: 0, count: length)
        let result = data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) -> Int32? in
            if let bodyAddress = body.baseAddress, body.count > 0 {
                let pointer = bodyAddress.assumingMemoryBound(to: UInt8.self)
                return SecRandomCopyBytes(kSecRandomDefault, 32, pointer)
            } else {
                return nil
            }
        }
        if let notNilResult = result, notNilResult == errSecSuccess {
            return data
        }
    }
    return nil
}

랜덤 변수를 만드는 메서드를 만들어주자. 주의할점은 128~256 비트 크기 내의 32비트 단위로 자른 값만 허용이 된다. (128,
160, 192, 224, 256)

 



2. S의 SHA-256 해시값 중에서 앞(왼쪽)에서 S의 길이 / 32비트만큼을 체크섬으로 만든다.

func genMnemonicsFromEntropy(entropy: Data) -> [String]? {
    let checksum = entropy.sha256() // 랜덤한 값인 entropy를 sha256알고리즘을 이용해 해시해주고
    let checksumBits = entropy.count*8/32 
    let checksumData = checksum[0 ..< (checksumBits + 7)/8 ] // 2. 가장 앞의 32비트를 체크썸으로 만들어준다.
    ....
}

 



3. 2번에서 만든 체크섬을 S의 끝에 추가한다.

func genMnemonicsFromEntropy(entropy: Data) -> [String]? {
    let checksum = entropy.sha256()
    let checksumBits = entropy.count*8/32
    let checksumData = checksum[0 ..< (checksumBits + 7)/8 ]
    var fullEntropy = Data()
    fullEntropy.append(entropy) // S를 만들고
    fullEntropy.append(checksumData) // 3. S의 끝에 checksum을 추가한다. 
    
    ....
}

 

 



4. 3번에서 만든 시퀀스와 체크섬의 연결을 11 bits 단위로 자른다.

func genMnemonicsFromEntropy(entropy: Data) -> [String]? {
    let checksum = entropy.sha256()
    let checksumBits = entropy.count*8/32
    let checksumData = checksum[0 ..< (checksumBits + 7)/8 ]
    var fullEntropy = Data()
    fullEntropy.append(entropy)
    fullEntropy.append(checksumData)
        
    var returnValue = [String]()
    for i in 0 ..< fullEntropy.count*8/11 { 
        guard let bits = fullEntropy.bitsInRange(i*11, 11) else { return nil } // 4. 11비트 단위로 자르자.
		
        ...
    }
        
    return returnValue
}

 

 


5. 각 각의 11비트를 2048(2^11)개의 미리 정의된 단어로 치환한다.

func genMnemonicsFromEntropy(entropy: Data) -> [String]? {
    let checksum = entropy.sha256()
    let checksumBits = entropy.count*8/32
    let checksumData = checksum[0 ..< (checksumBits + 7)/8 ]
    var fullEntropy = Data()
    fullEntropy.append(entropy)
    fullEntropy.append(checksumData)
        
    var returnValue = [String]()
    for i in 0 ..< fullEntropy.count*8/11 {
        guard let bits = fullEntropy.bitsInRange(i*11, 11) else { return nil }
        let index = Int(bits)
        guard Words.englishWords.count > index else { return nil }
        let word = Words.englishWords[index] // 5. 각 각의 11비트를 2048(2^11)개의 미리 정의된 단어로 치환한다.
        returnValue.append(word) // 결과적으로 반환해줄 니모닉 배열에 단어를 더해주자.
    }
        
    return returnValue
}

 

 


6. 단어 시퀀스로부터 순서를 유지하면서 니모닉 코드를 생성한다.

니모닉 완성 !

 

 

니모닉 -> 엔트로피 변환

역순으로 실행 해주면 된다.

for mnemonic in mnemonics {
     guard let idx = Words.englishWords.firstIndex(of: mnemonic) else { return nil }
     let idxAsInt = Words.englishWords.startIndex.distance(to: idx)
     let stringForm = String(UInt16(idxAsInt), radix: 2).leftPadding(toLength: 11, withPad: "0")
     bitString.append(stringForm)
}

니모닉을 2진수로 변환한 후

let checksumBits = bitString[(bitString.count - bitString.count/33) ..< bitString.count]
guard let entropy = entropyBits.interpretAsBinaryData() else {
    return nil
}
let checksum = String(entropy.sha256().bitsInRange(0, checksumBits.count)!, radix: 2).leftPadding(toLength: checksumBits.count, withPad: "0")
if checksum != checksumBits {
    return nil
}

checksum이 맞는지 확인한다.

 

 

 

 

원문 출력 성공









----


모든 소스 코드는
https://github.com/MyiOSPlayground/Mnemonic

 

GitHub - MyiOSPlayground/Mnemonic: Mnemonic

Mnemonic. Contribute to MyiOSPlayground/Mnemonic development by creating an account on GitHub.

github.com

이곳에서 확인하실 수 있습니다.






코드의 대부분은
https://github.com/skywinder/web3swift

 

GitHub - skywinder/web3swift: Elegant Web3js functionality in Swift. Native ABI parsing and smart contract interactions.

Elegant Web3js functionality in Swift. Native ABI parsing and smart contract interactions. - GitHub - skywinder/web3swift: Elegant Web3js functionality in Swift. Native ABI parsing and smart contra...

github.com

이곳을 참조하였습니다.









공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함