mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: ['1.24']
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
go mod download
|
||||
make install-tools
|
||||
|
||||
- name: Format check
|
||||
run: |
|
||||
gofmt -s -l .
|
||||
test -z "$(gofmt -s -l .)"
|
||||
|
||||
- name: Lint
|
||||
run: make lint
|
||||
|
||||
- name: Run tests
|
||||
run: make test-coverage
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage.out
|
||||
fail_ci_if_error: true
|
||||
|
||||
- name: Run benchmarks
|
||||
run: make bench
|
||||
|
||||
security:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Run Gosec Security Scanner
|
||||
uses: securego/gosec@master
|
||||
with:
|
||||
args: ./...
|
||||
|
||||
- name: Run Nancy vulnerability scanner
|
||||
run: |
|
||||
go install github.com/sonatype-nexus-community/nancy@latest
|
||||
go list -json -m all | nancy sleuth
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
go-version: ['1.21', '1.22']
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Build
|
||||
run: make build
|
||||
|
||||
- name: Verify module
|
||||
run: make verify
|
||||
@@ -0,0 +1,83 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
- 'crypto/v*.*.*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test Before Release
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
go mod download
|
||||
make install-tools
|
||||
|
||||
- name: Run tests
|
||||
run: make test
|
||||
|
||||
- name: Run linter
|
||||
run: make lint
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Build binaries
|
||||
run: |
|
||||
# Build for multiple platforms
|
||||
GOOS=linux GOARCH=amd64 go build -o dist/crypto-linux-amd64 ./...
|
||||
GOOS=linux GOARCH=arm64 go build -o dist/crypto-linux-arm64 ./...
|
||||
GOOS=darwin GOARCH=amd64 go build -o dist/crypto-darwin-amd64 ./...
|
||||
GOOS=darwin GOARCH=arm64 go build -o dist/crypto-darwin-arm64 ./...
|
||||
GOOS=windows GOARCH=amd64 go build -o dist/crypto-windows-amd64.exe ./...
|
||||
|
||||
- name: Generate changelog
|
||||
id: changelog
|
||||
uses: mikepenz/release-changelog-builder-action@v4
|
||||
with:
|
||||
configuration: ".github/changelog-config.json"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body: ${{ steps.changelog.outputs.changelog }}
|
||||
files: |
|
||||
dist/*
|
||||
draft: false
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Update Go Module Index
|
||||
run: |
|
||||
curl -X POST https://proxy.golang.org/github.com/luxfi/crypto/@v/${{ github.ref_name }}.info
|
||||
@@ -0,0 +1,72 @@
|
||||
# Makefile for luxfi/crypto module
|
||||
|
||||
.PHONY: all build test clean fmt lint install-tools test-coverage
|
||||
|
||||
# Variables
|
||||
GOBIN := $(shell go env GOPATH)/bin
|
||||
GOLANGCI_LINT_VERSION := v1.54.2
|
||||
COVERAGE_FILE := coverage.out
|
||||
COVERAGE_HTML := coverage.html
|
||||
|
||||
# Default target
|
||||
all: clean fmt lint test build
|
||||
|
||||
# Build the module
|
||||
build:
|
||||
@echo "Building crypto module..."
|
||||
@go build -v ./...
|
||||
|
||||
# Run tests
|
||||
test:
|
||||
@echo "Running tests..."
|
||||
@go test -v -race -timeout=10m ./...
|
||||
|
||||
# Run tests with coverage
|
||||
test-coverage:
|
||||
@echo "Running tests with coverage..."
|
||||
@go test -v -race -timeout=10m -coverprofile=$(COVERAGE_FILE) -covermode=atomic ./...
|
||||
@go tool cover -html=$(COVERAGE_FILE) -o $(COVERAGE_HTML)
|
||||
@echo "Coverage report generated: $(COVERAGE_HTML)"
|
||||
|
||||
# Format code
|
||||
fmt:
|
||||
@echo "Formatting code..."
|
||||
@go fmt ./...
|
||||
@go mod tidy
|
||||
|
||||
# Run linter
|
||||
lint: install-tools
|
||||
@echo "Running linter..."
|
||||
@$(GOBIN)/golangci-lint run ./...
|
||||
|
||||
# Install development tools
|
||||
install-tools:
|
||||
@echo "Installing development tools..."
|
||||
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
@echo "Cleaning..."
|
||||
@go clean -cache -testcache
|
||||
@rm -f $(COVERAGE_FILE) $(COVERAGE_HTML)
|
||||
|
||||
# Run benchmarks
|
||||
bench:
|
||||
@echo "Running benchmarks..."
|
||||
@go test -bench=. -benchmem ./...
|
||||
|
||||
# Check for security vulnerabilities
|
||||
security:
|
||||
@echo "Checking for vulnerabilities..."
|
||||
@go list -json -m all | nancy sleuth
|
||||
|
||||
# Update dependencies
|
||||
deps:
|
||||
@echo "Updating dependencies..."
|
||||
@go get -u -t ./...
|
||||
@go mod tidy
|
||||
|
||||
# Verify module
|
||||
verify:
|
||||
@echo "Verifying module..."
|
||||
@go mod verify
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/luxfi/node/utils"
|
||||
"github.com/luxfi/crypto"
|
||||
"github.com/luxfi/crypto/bls/blstest"
|
||||
)
|
||||
|
||||
@@ -19,7 +19,7 @@ func BenchmarkVerify(b *testing.B) {
|
||||
|
||||
for _, messageSize := range blstest.BenchmarkSizes {
|
||||
b.Run(strconv.Itoa(messageSize), func(b *testing.B) {
|
||||
message := utils.RandomBytes(messageSize)
|
||||
message := crypto.RandomBytes(messageSize)
|
||||
signature := sign(privateKey, message)
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -99,7 +99,7 @@ func BenchmarkPublicKeyFromValidUncompressedBytes(b *testing.B) {
|
||||
func BenchmarkSignatureFromBytes(b *testing.B) {
|
||||
sk := newKey(require.New(b))
|
||||
|
||||
message := utils.RandomBytes(32)
|
||||
message := crypto.RandomBytes(32)
|
||||
signature := sign(sk, message)
|
||||
signatureBytes := SignatureToBytes(signature)
|
||||
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/luxfi/node/utils"
|
||||
"github.com/luxfi/crypto"
|
||||
|
||||
blst "github.com/supranational/blst/bindings/go"
|
||||
)
|
||||
@@ -48,7 +48,7 @@ func TestAggregationThreshold(t *testing.T) {
|
||||
}
|
||||
|
||||
// The transaction's unsigned bytes are publicly known.
|
||||
msg := utils.RandomBytes(1234)
|
||||
msg := crypto.RandomBytes(1234)
|
||||
|
||||
// People may attempt time sign the transaction.
|
||||
sigs := []*Signature{
|
||||
|
||||
+2
-2
@@ -9,13 +9,13 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/luxfi/node/utils"
|
||||
"github.com/luxfi/crypto"
|
||||
)
|
||||
|
||||
func TestPublicKeyFromCompressedBytesWrongSize(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
pkBytes := utils.RandomBytes(PublicKeyLen + 1)
|
||||
pkBytes := crypto.RandomBytes(PublicKeyLen + 1)
|
||||
_, err := PublicKeyFromCompressedBytes(pkBytes)
|
||||
require.ErrorIs(err, ErrFailedPublicKeyDecompress)
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/luxfi/node/utils"
|
||||
"github.com/luxfi/crypto"
|
||||
)
|
||||
|
||||
func TestSignatureBytes(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
msg := utils.RandomBytes(1234)
|
||||
msg := crypto.RandomBytes(1234)
|
||||
|
||||
sk := newKey(require)
|
||||
sig := sign(sk, msg)
|
||||
@@ -31,7 +31,7 @@ func TestSignatureBytes(t *testing.T) {
|
||||
func TestAggregateSignaturesNoop(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
msg := utils.RandomBytes(1234)
|
||||
msg := crypto.RandomBytes(1234)
|
||||
|
||||
sk := newKey(require)
|
||||
sig := sign(sk, msg)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/luxfi/node/utils"
|
||||
"github.com/luxfi/crypto"
|
||||
"github.com/luxfi/crypto/bls/blstest"
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ func BenchmarkSign(b *testing.B) {
|
||||
signer := NewSigner(require.New(b))
|
||||
for _, messageSize := range blstest.BenchmarkSizes {
|
||||
b.Run(strconv.Itoa(messageSize), func(b *testing.B) {
|
||||
message := utils.RandomBytes(messageSize)
|
||||
message := crypto.RandomBytes(messageSize)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/luxfi/node/utils"
|
||||
"github.com/luxfi/crypto"
|
||||
|
||||
blst "github.com/supranational/blst/bindings/go"
|
||||
)
|
||||
@@ -27,7 +27,7 @@ func TestSecretKeyFromBytesZero(t *testing.T) {
|
||||
func TestSecretKeyFromBytesWrongSize(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
skBytes := utils.RandomBytes(SecretKeyLen + 1)
|
||||
skBytes := crypto.RandomBytes(SecretKeyLen + 1)
|
||||
_, err := FromBytes(skBytes)
|
||||
require.ErrorIs(err, ErrFailedSecretKeyDeserialize)
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func TestSecretKeyFromBytesWrongSize(t *testing.T) {
|
||||
func TestSecretKeyBytes(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
msg := utils.RandomBytes(1234)
|
||||
msg := crypto.RandomBytes(1234)
|
||||
|
||||
sk, err := New()
|
||||
require.NoError(err)
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/luxfi/node/proto/pb/signer"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/bls/signer/localsigner"
|
||||
"github.com/luxfi/node/proto/pb/signer"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2020-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package cb58
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/mr-tron/base58/base58"
|
||||
|
||||
"github.com/luxfi/crypto/hashing"
|
||||
)
|
||||
|
||||
const checksumLen = 4
|
||||
|
||||
var (
|
||||
ErrBase58Decoding = errors.New("base58 decoding error")
|
||||
ErrMissingChecksum = errors.New("input string is smaller than the checksum size")
|
||||
ErrBadChecksum = errors.New("invalid input checksum")
|
||||
errEncodingOverFlow = errors.New("encoding overflow")
|
||||
)
|
||||
|
||||
// Encode [bytes] to a string using cb58 format.
|
||||
// [bytes] may be nil, in which case it will be treated the same as an empty
|
||||
// slice.
|
||||
func Encode(bytes []byte) (string, error) {
|
||||
bytesLen := len(bytes)
|
||||
if bytesLen > math.MaxInt32-checksumLen {
|
||||
return "", errEncodingOverFlow
|
||||
}
|
||||
checked := make([]byte, bytesLen+checksumLen)
|
||||
copy(checked, bytes)
|
||||
copy(checked[len(bytes):], hashing.Checksum(bytes, checksumLen))
|
||||
return base58.Encode(checked), nil
|
||||
}
|
||||
|
||||
// Decode [str] to bytes from cb58.
|
||||
func Decode(str string) ([]byte, error) {
|
||||
decodedBytes, err := base58.Decode(str)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", ErrBase58Decoding, err)
|
||||
}
|
||||
if len(decodedBytes) < checksumLen {
|
||||
return nil, ErrMissingChecksum
|
||||
}
|
||||
// Verify the checksum
|
||||
rawBytes := decodedBytes[:len(decodedBytes)-checksumLen]
|
||||
checksum := decodedBytes[len(decodedBytes)-checksumLen:]
|
||||
if !bytes.Equal(checksum, hashing.Checksum(rawBytes, checksumLen)) {
|
||||
return nil, ErrBadChecksum
|
||||
}
|
||||
return rawBytes, nil
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (C) 2020-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package cb58
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Test encoding bytes to a string and decoding back to bytes
|
||||
func TestEncodeDecode(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
type test struct {
|
||||
bytes []byte
|
||||
str string
|
||||
}
|
||||
|
||||
id := [32]byte{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, 32}
|
||||
tests := []test{
|
||||
{
|
||||
nil,
|
||||
"45PJLL",
|
||||
},
|
||||
{
|
||||
[]byte{},
|
||||
"45PJLL",
|
||||
},
|
||||
{
|
||||
[]byte{0},
|
||||
"1c7hwa",
|
||||
},
|
||||
{
|
||||
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255},
|
||||
"1NVSVezva3bAtJesnUj",
|
||||
},
|
||||
{
|
||||
id[:],
|
||||
"SkB92YpWm4Q2ijQHH34cqbKkCZWszsiQgHVjtNeFF2HdvDQU",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
// Encode the bytes
|
||||
strResult, err := Encode(test.bytes)
|
||||
require.NoError(err)
|
||||
// Make sure the string repr. is what we expected
|
||||
require.Equal(test.str, strResult)
|
||||
// Decode the string
|
||||
bytesResult, err := Decode(strResult)
|
||||
require.NoError(err)
|
||||
// Make sure we got the same bytes back
|
||||
require.True(bytes.Equal(test.bytes, bytesResult))
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzEncodeDecode(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
require := require.New(t)
|
||||
|
||||
// Encode bytes to string
|
||||
dataStr, err := Encode(data)
|
||||
require.NoError(err)
|
||||
|
||||
// Decode string to bytes
|
||||
gotData, err := Decode(dataStr)
|
||||
require.NoError(err)
|
||||
|
||||
require.Equal(data, gotData)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2020-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package crypto
|
||||
|
||||
import gocrypto "crypto"
|
||||
|
||||
// Certificate represents a TLS certificate
|
||||
// This is a minimal representation needed for NodeID generation
|
||||
type Certificate struct {
|
||||
// Raw contains the complete ASN.1 DER content of the certificate
|
||||
Raw []byte
|
||||
// PublicKey contains the public key from the certificate
|
||||
PublicKey gocrypto.PublicKey
|
||||
}
|
||||
@@ -11,6 +11,7 @@ require (
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267
|
||||
github.com/luxfi/geth v1.16.2
|
||||
github.com/luxfi/node v1.15.0
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/supranational/blst v0.3.15
|
||||
golang.org/x/crypto v0.40.0
|
||||
|
||||
@@ -38,6 +38,8 @@ github.com/luxfi/geth v1.16.2 h1:rTzLxDe2Zbt7vv3j1rRBt6jnC1Alf1Hglq25cdj+C0Q=
|
||||
github.com/luxfi/geth v1.16.2/go.mod h1:XqDpjw2AlF38QOc91CM/MaUe5RNun7Cqe+WS4qxMKcQ=
|
||||
github.com/luxfi/node v1.15.0 h1:sSN6vGnoRb4IMFxQjhT9rFw/S9Vprsdq9zYxg9DMsRI=
|
||||
github.com/luxfi/node v1.15.0/go.mod h1:wTa2R9wr4DyWVn2c4XlkT1uzpggjFTnyXW9mtRr+pYI=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (C) 2020-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package hashing
|
||||
|
||||
// Hasher is an interface to compute a hash value.
|
||||
type Hasher interface {
|
||||
// Hash takes a string and computes its hash value.
|
||||
// Values must be computed deterministically.
|
||||
Hash([]byte) uint64
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright (C) 2020-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package hashing
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
// This file generates addresses from public keys with ripemd160. Though ripemd160 is not
|
||||
// generally recommended for use, the small size of the public key input is considered harder to
|
||||
// attack than larger payloads.
|
||||
//
|
||||
// Bitcoin similarly uses ripemd160 to generate addresses from public keys.
|
||||
//
|
||||
// Reference: https://online.tugraz.at/tug_online/voe_main2.getvolltext?pCurrPk=17675
|
||||
"golang.org/x/crypto/ripemd160" //nolint:gosec
|
||||
)
|
||||
|
||||
const (
|
||||
HashLen = sha256.Size
|
||||
AddrLen = ripemd160.Size
|
||||
)
|
||||
|
||||
var ErrInvalidHashLen = errors.New("invalid hash length")
|
||||
|
||||
// Hash256 A 256 bit long hash value.
|
||||
type Hash256 = [HashLen]byte
|
||||
|
||||
// Hash160 A 160 bit long hash value.
|
||||
type Hash160 = [ripemd160.Size]byte
|
||||
|
||||
// ComputeHash256Array computes a cryptographically strong 256 bit hash of the
|
||||
// input byte slice.
|
||||
func ComputeHash256Array(buf []byte) Hash256 {
|
||||
return sha256.Sum256(buf)
|
||||
}
|
||||
|
||||
// ComputeHash256 computes a cryptographically strong 256 bit hash of the input
|
||||
// byte slice.
|
||||
func ComputeHash256(buf []byte) []byte {
|
||||
arr := ComputeHash256Array(buf)
|
||||
return arr[:]
|
||||
}
|
||||
|
||||
// ComputeHash160Array computes a cryptographically strong 160 bit hash of the
|
||||
// input byte slice.
|
||||
func ComputeHash160Array(buf []byte) Hash160 {
|
||||
h, err := ToHash160(ComputeHash160(buf))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// ComputeHash160 computes a cryptographically strong 160 bit hash of the input
|
||||
// byte slice.
|
||||
func ComputeHash160(buf []byte) []byte {
|
||||
// See the comment on the ripemd160 import as to why the risk of use is
|
||||
// considered acceptable.
|
||||
ripe := ripemd160.New() //nolint:gosec
|
||||
_, err := io.Writer(ripe).Write(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ripe.Sum(nil)
|
||||
}
|
||||
|
||||
// Checksum creates a checksum of [length] bytes from the 256 bit hash of the
|
||||
// byte slice.
|
||||
//
|
||||
// Returns: the lower [length] bytes of the hash
|
||||
// Panics if length > 32.
|
||||
func Checksum(bytes []byte, length int) []byte {
|
||||
hash := ComputeHash256Array(bytes)
|
||||
return hash[len(hash)-length:]
|
||||
}
|
||||
|
||||
func ToHash256(bytes []byte) (Hash256, error) {
|
||||
hash := Hash256{}
|
||||
if bytesLen := len(bytes); bytesLen != HashLen {
|
||||
return hash, fmt.Errorf("%w: expected 32 bytes but got %d", ErrInvalidHashLen, bytesLen)
|
||||
}
|
||||
copy(hash[:], bytes)
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func ToHash160(bytes []byte) (Hash160, error) {
|
||||
hash := Hash160{}
|
||||
if bytesLen := len(bytes); bytesLen != ripemd160.Size {
|
||||
return hash, fmt.Errorf("%w: expected 20 bytes but got %d", ErrInvalidHashLen, bytesLen)
|
||||
}
|
||||
copy(hash[:], bytes)
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func PubkeyBytesToAddress(key []byte) []byte {
|
||||
return ComputeHash160(ComputeHash256(key))
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2020-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
// RandomBytes returns a slice of n random bytes
|
||||
func RandomBytes(n int) []byte {
|
||||
bytes := make([]byte, n)
|
||||
// #nosec G404 - we don't need cryptographic randomness for test data
|
||||
_, _ = rand.Read(bytes)
|
||||
return bytes
|
||||
}
|
||||
Reference in New Issue
Block a user