Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 코드리뷰
- 싱글톤패턴
- 코드스테이츠
- 부트캠프
- 스테이트머신패턴
- 블록체인
- RBAC
- 일시정지
- 토큰노믹스
- 웹툰
- 프록시패턴
- github
- github 에러
- 팩토리패턴
- 투표
- 옵저버패턴
- git add
- 솔리디티
- 인센티브 기반 커뮤니티
- 디자인 패턴
- 재진입
- solidity
- 팀 프로젝트
- 멀티시그
- 트러블슈팅
- git commit
- 회로차단
- 배팅
- 업그레이더블 컨트랙트
Archives
- Today
- Total
보다 더 생생한 기록
[GO] 포인터 사용 공식 (feat. ecdsa.Verify 함수) 본문
아래는 자체라이브러리 crypto 중 ecdsa.Verify() 함수의 기본 형식이다.
func ecdsa.Verify(pub *ecdsa.PublicKey, hash []byte, r *big.Int, s *big.Int) bool
이걸 사용하기 위해선, privateKey struct내에서 PublicKey를 꺼내야한다.
ecdsa.Verify(&privateKey.PublicKey, hashAsBytes, r, s)
GO 언어 초심자인 나는 여기서 궁금증이 생겼다.
왜 굳이 PublicKey, r, s 를 포인터로 받아야 하는가?
함수의 존재 목적과 돌아가는 방식을 보면, 포인터를 이용해서 수정하는 것도 아니고, 그냥 검증하는 함수일 뿐인데 말이다.
또한 복사본 자체도 메모리를 많이 차지할 것도 아닌것 같은데 굳이 포인터를?
구글링을 해본 결과, 3가지 정도의 이유가 나왔다.
1. 성능
포인터를 사용하면 데이터 복사본을 만들 필요가 없다. 복잡한 구조체나 큰 데이터 구조를 값으로 전달하면, 함수를 호출할 때마다 그 데이터의 복사본이 생성되어야 한다. 이로 인해 추가적인 메모리 사용과 CPU 시간이 소요되는데, 이때 포인터를 사용하면 실제 데이터의 위치를 가리키기 때문에 이러한 부가적인 비용을 피할 수 있다.
C++ 언어로 개발 했을때도 포인터를 사용했었지만, 너무 오래전이라 메모리 뿐 아니라 시간도 감축된다는 것을 망각하고 있었다.
최근 들어 js만 사용하다보니 포인터의 필요성을 잊었나보다.
2. 일관성
고언어의 표준 라이브러리에서는 종종 포인터를 사용하여 복잡한 구조체를 함수에 전달한다. 이는 일관성을 유지하고 개발자에게 예상 가능한 API를 제공하는데 도움이 된다.
이 내용 덕분에 privateKey struct를 한번더 보게 되었다.
복잡하다고 볼 수는 없지만, big.Int라는 큰 숫자를 가진 형식을 가지고 있기 때문에, 포인터를 사용한 것으로 보인다.
type PrivateKey struct {
PublicKey
D *big.Int
}
type PublicKey struct {
elliptic.Curve
X, Y *big.Int
}
또한 일관성을 유지하기 위함이라는 글을 보고 go언어 공식 패키지에 들어가서 crypto/ecdsa를 찾아보았다.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error)
func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error)
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool
func VerifyASN1(pub *PublicKey, hash, sig []byte) bool
type PrivateKey
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error)
func (k *PrivateKey) ECDH() (*ecdh.PrivateKey, error)
func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool
func (priv *PrivateKey) Public() crypto.PublicKey
func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error)
type PublicKey
func (k *PublicKey) ECDH() (*ecdh.PublicKey, error)
func (pub *PublicKey) Equal(x crypto.PublicKey) bool
구조체는 전부 포인터로 받고 있는게 보이고, 마지막 함수는 x를 받고 있는데, 이는 crypto.PrivateKey의 인터페이스 타입이다. 포인터가 아닌 다른것들도 받아야 하기에 이렇게 설정해 둔듯 하다.
결론 : 일관성 하나는 잘 지키는 듯 하다.
3. 데이터 변경
함수 내에서 구조체를 수정해야 할 경우에는 포인터를 사용해야만 원래의 데이터에 영향을 줄 수 있다.
3번은 위 함수에서 이미 수정할 내용이 없는걸 확인했으니 패스.
'Go' 카테고리의 다른 글
[GO] [코드리뷰] 블록체인 구축 코드 리뷰 (지갑과 서명) - (4)(上) (0) | 2023.09.25 |
---|---|
[GO] [코드리뷰] 블록체인 구축 코드 리뷰 (트랜잭션) - (3) (0) | 2023.09.25 |
[GO] 중첩반복문 탈출 방법 : label (0) | 2023.09.13 |
[GO] 중첩반복문 탈출 방법 : label (0) | 2023.09.13 |
[GO] Method VS Function 선언 선택 공식, 함수 또는 메서드가 어떤 역할 하는지 선언만 보고 간단하게 파악하기 (0) | 2023.09.08 |