aleo_oracle_sdk

package module
v1.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2024 License: GPL-3.0 Imports: 15 Imported by: 0

README

Oracle SDK for Golang

Go Reference

This repository contains a Golang client SDK for Aleo Oracle.

For documentation, see docs.aleooracle.xyz.

Disclaimer: Experimental software

This repository is a part of an experimental project and should be treated as such. It has not undergone any formal security audits yet. While the software contained herein may not be necessarily dangerous to your PC, it may produce unreliable results or unexpected behavior. Users are advised to exercise caution when using this software and to not deploy it in production environments without thorough testing and review. The maintainers of this repository cannot be held liable for any damages or security breaches that may occur as a result of its use. By accessing and using the contents of this repository, you agree to do so at your own risk.

Documentation

Overview

This package provides a client for Aleo Oracle.

This client is for developing applications that need to consume data trustlessly from an HTTPS source and securely express them in Web3.

Oracles provide a way for the decentralized Web3 ecosystem to access existing data sources, legacy systems, and advanced computations, but come with a downside of having to trust the oracle owner. Unlike them, Aleo Oracle is trustless and doesn't have an owner, thus solving the problem.

This SDK can be used with an Aleo oracle contract to expose data to Aleo blockchain in a trustless way using TEEs (Trusted Execution Environment) like Intel SGX and Aleo's SnarkVM.

Most of the heavy lifting is done on the backend side, where one or more instances of notarization backends create attestations on requested data, which can be verified locally and remotely, and in a contract.

Terms

TEE - Trusted Execution Environment - is an area on the main processor of a device that is separated from the system's main operating system. It ensures data is stored, processed and protected in a secure environment.

Attestation Report - A document that confirms the enclave is running a particular piece of code or specific container.

Notarization Backend - Oracle Backend that is running in TEE. This backend makes a request to the Attestation Target, extracts data from the response and creates an Attestation Report, which includes data and how this data was obtained.

Verification Backend - Backend that is verifying that an Attestation Report is valid and has not been modified.

Attestation Target - A remote server which provides data that you want to notarize. For example, an exchange with currency rates.

Attestation Response - A response containing the data required for notarization that backend gets when it requests an Attestation Target with the provided Attestation Request.

Attestation Request - Information on how to reproduce the requests to an Attestation Target. From URL and request method to all of the request headers.

Attestation Data - Data extracted from an Attestation Response, that you want to notarize. For example, BTC to USDT exchange rate.

Example
// First, we configure the client
config := &ClientConfig{
	NotarizerConfig: &CustomBackendConfig{
		Address: "sgx.aleooracle.xyz",
		HTTPS:   true,
		Resolve: true,
	},
	VerifierConfig: &CustomBackendConfig{
		Address: "verifier.aleooracle.xyz",
		HTTPS:   true,
		Resolve: true,
	},
	Logger: log.Default(),
}

// Create a client
client, err := NewClient(config)
if err != nil {
	log.Fatalln(err)
}

// Fetch enclave info for all attesters
infoList, errList := client.GetEnclavesInfo(nil)
if errList != nil {
	log.Fatalln(errList)
}

for _, info := range infoList {
	log.Println()
	log.Println("Enclave info:", info, info.SgxInfo)
	log.Println()
}

// Build attestation request
req := &AttestationRequest{
	URL:            "archive-api.open-meteo.com/v1/archive?latitude=38.9072&longitude=77.0369&start_date=2023-11-20&end_date=2023-11-21&daily=rain_sum",
	ResponseFormat: "json",
	RequestMethod:  http.MethodGet,
	Selector:       "daily.rain_sum.[0]",
	EncodingOptions: EncodingOptions{
		Value:     "float",
		Precision: 2,
	},
}

// Use TestSelector in development if you need to figure out what kind of response you're getting from the attestation target
responses, errList := client.TestSelector(req, nil)
if errList != nil {
	log.Fatalln(errList)
}

log.Println()
log.Println("Test selector result:", *responses[0])
log.Println()

// Use attested notarization once you've figured out what request options you want
timeDeviation := int64(500) // 500ms
options := &NotarizationOptions{
	AttestationContext:  context.Background(),
	VerificationContext: context.Background(),
	DataShouldMatch:     true,
	MaxTimeDeviation:    &timeDeviation,
}

attestations, errList := client.Notarize(req, options)
if errList != nil {
	log.Fatalln(errList)
}

// The URL was notarized, the extracted result was attested by the enclaves, enclave signatures were verified by the verifier, you can now use the data
log.Println()
log.Println("Data extracted from the URL using the selector:", attestations[0].AttestationData)
log.Println()

log.Println()
log.Println("Attestation response prepared for using in an Aleo contract:", attestations[0].OracleData.UserData)
log.Println()
Output:

Index

Examples

Constants

View Source
const (
	// Request timeout used by default for Client's methods
	DEFAULT_TIMEOUT = 5 * time.Second
)
View Source
const (
	REPORT_TYPE_SGX = "sgx"
)

Variables

View Source
var (
	DEFAULT_NOTARIZATION_BACKENDS = []*CustomBackendConfig{
		&CustomBackendConfig{
			Address:   "sgx.aleooracle.xyz",
			Port:      443,
			HTTPS:     true,
			ApiPrefix: "",
			Resolve:   true,
		},
	}

	DEFAULT_VERIFICATION_BACKEND = &CustomBackendConfig{
		Address:   "verifier.aleooracle.xyz",
		Port:      443,
		HTTPS:     true,
		ApiPrefix: "",
		Resolve:   true,
	}
)
View Source
var (
	// Default headers that will be added to the attestation request.
	DEFAULT_NOTARIZATION_HEADERS = map[string]string{
		"Accept":                    "*/*",
		"User-Agent":                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
		"Upgrade-Insecure-Requests": "1",
		"DNT":                       "1",
	}
)

Functions

This section is empty.

Types

type AttestationRequest

type AttestationRequest struct {
	// URL of a resource to attest - attestation target. Must not include schema - HTTPS is assumed
	URL string `json:"url"`

	// HTTP method to be used for a request to the attestation target. Supports only GET and POST
	RequestMethod string `json:"requestMethod"`

	// Optional element selector for extracting data from the attestation resource - XPath for HTML, JSON key path for JSON.
	// When empty, the oracle attests to the whole response unless the response size limit of **4kb** is hit.
	//
	// JSON key path example - given an example JSON
	// {
	//  "primitive": "value",
	//  "list": [123, 223, 3],
	//  "dictionary": {
	//    "key1": "value1",
	//    "key2": "value2"
	//  }
	// }
	// 	- selector "primitive" will select "value"
	// 	- selector "list.[1]"" will select "223"
	// 	- selector "dictionary.key2" will select "value2".
	Selector string `json:"selector,omitempty"`

	// Expected attestation target response format
	ResponseFormat ResponseFormat `json:"responseFormat"`

	// When ResponseFormat is RESPONSE_FORMAT_HTML, this field indicates the type of extraction
	// for the response after applying the selector.
	HtmlResultType *HtmlResultType `json:"htmlResultType,omitempty"`

	// Information about how to encode Attestation Data to Aleo-compatible format
	EncodingOptions EncodingOptions `json:"encodingOptions"`

	// Can be used to provide a POST request body for the attestation target request.
	//
	// Has effect only when RequestMethod is POST.
	//
	RequestBody *string `json:"requestBody,omitempty"`

	// Can be used to provide a Content-Type request header for the attestation target request.
	//
	// Has effect only when RequestMethod is POST.
	RequestContentType *string `json:"requestContentType,omitempty"`

	// Optional dictionary of HTTP headers to add to the request to attestation target.
	//
	// Value of headers which might contain sensitive information (like "Authorization", "X-Auth-Token" or "Cookie")
	// and any non-standard headers used by attestation target would be replaced with "*****" in attestation report.
	//
	// This SDK will use some default request headers like User-Agent. See DEFAULT_NOTARIZATION_HEADERS.
	//
	RequestHeaders map[string]string `json:"requestHeaders,omitempty"`
}

AttestationRequest contains information about a request to the attestation target, how the attestation target is expected to respond and how to parse its response to extract target data.

IMPORTANT: Max allowed field size is 4kb!

type AttestationResponse

type AttestationResponse struct {
	// URL of the Notarization Backend the report came from.
	EnclaveUrl string `json:"enclaveUrl"`

	// Attestation Report in Base64 encoding, created by the Trusted Execution Environment using the extracted data.
	AttestationReport string `json:"attestationReport"`

	// Which TEE produced the attestation report. Only Intel SGX is supported at the moment with possibility to have more later.
	ReportType string `json:"reportType"`

	// Data extracted from the attestation target's response using the provided selector. The data is always a string, as seen in the raw HTTP response.
	AttestationData string `json:"attestationData"`

	// Full response body received in the attestation target's response.
	ResponseBody string `json:"responseBody"`

	// Status code of the attestation target's response.
	ResponseStatusCode int `json:"responseStatusCode"`

	// Reserved.
	Nonce string `json:"nonce,omitempty"`

	// Unix timestamp of the attestation date time as seen by the attestation server (not attestation target).
	Timestamp int64 `json:"timestamp"`

	// Information that can be used in your Aleo program, like Aleo-formatted attestation report.
	OracleData OracleData `json:"oracleData"`

	// Original attestation request included in the AttestationReport hash.
	// Keep in mind that all request headers that are not in the list of known headers will be replaced with "*****"".
	// Also the order might be different from the original request (which is important when calculating a hash of AttestationReport).
	AttestationRequest *AttestationRequest `json:"attestationRequest"`
}

AttestationResponse is notarization backend's response to an attestation request

type Client

type Client struct {
	// contains filtered or unexported fields
}

Aleo Oracle client.

func NewClient

func NewClient(config *ClientConfig) (*Client, error)

NewClient creates a new client using the provided configuration. Configuration is optional. If configuration is not provided, will use 1 notarizer and a verifier hosted by the developers, no logging, http.DefaultTransport for transport.

func (*Client) GetEnclavesInfo

func (c *Client) GetEnclavesInfo(options *EnclaveInfoOptions) ([]*EnclaveInfo, []error)

GetEnclavesInfo requests information about the enclaves that the Notarization Backends are running in.

Can be used to get such important information as security level or Enclave Unique ID, which can be used to verify that Notarization Backend is running the expected version of the code.

Options are optional, will use 5-second timeout context if options are nil.

func (*Client) Notarize

func (c *Client) Notarize(req *AttestationRequest, options *NotarizationOptions) ([]*AttestationResponse, []error)

Notarize requests attestation of data extracted from the provided URL using the provided selector. Attestation is created by one or more Trusted Execution Environments (TEE). If more than one is used, all attestation requests should succeed.

It is highly recommended to use time insensitive historic data for notarization. In case of using live data, other people might see different results when requesting the same url with the same parameters.

Use options to configure attestation. If not provided, will use default options - 5 sec timeouts, DataShouldMatch, no time deviation checks.

func (*Client) TestSelector

func (c *Client) TestSelector(req *AttestationRequest, options *TestSelectorOptions) ([]*TestSelectorResponse, []error)

TestSelector is a function that can be used to test your requests without performing attestation and verification.

Notarization Backend will try to request the attestation target and extract data with the provided selector. You can use the same request that you would use for Notarize to see if the Notarization Backend is able to get your data and correctly extract it. You will be able to see as a result the full ResponseBody, extracted data, response status code and errors if there are any.

Options are optional. If nil, will use a 5-second timeout context.

type ClientConfig

type ClientConfig struct {
	// NotarizerConfig is a an optional field for configuring the client to use a self-hosted Oracle Notarization service for testing.
	// If not provided, the client will use the default Oracle Notarization service/services hosted by the developer.
	NotarizerConfig *CustomBackendConfig

	// VerifierConfig is a an optional field for configuring the client to use a self-hosted Oracle Notarization Verification service.
	// If not provided, the client will use the default Oracle Notarization Verification service hosted by the developer.
	VerifierConfig *CustomBackendConfig

	// Optional Client logger. No logs will be used if not provided.
	Logger *log.Logger

	// Optional transport configuration. If not provided, the [http.DefaultTransport] will be used.
	Transport http.RoundTripper
}

ClientConfig contains client instantiation configuration.

type CustomBackendConfig

type CustomBackendConfig struct {
	// Domain name or IP address of the backend
	Address string

	// The port that the backend listens on for the API requests
	Port uint16

	// Whether the client should use HTTPS to connect to the backend
	HTTPS bool

	// Whether the client should resolve the backend (when it's a domain name).
	// If the domain name is resolved to more than one IP, then the requests will be
	// sent to all of the resolved servers, and the first response will be used.
	Resolve bool

	// Optional API prefix to use before the API endpoints
	ApiPrefix string
}

CustomBackendConfig is a configuration object for using custom notarizer or verifier.

type EnclaveInfo

type EnclaveInfo struct {
	json.Unmarshaler

	// Url of the Notarization Backend the report came from.
	EnclaveUrl string

	// TEE that backend is running in
	ReportType string

	// This is a public key of the report signing key that was generated in the enclave.
	// The signing key is used to create Schnorr signatures,
	// and the public key is to be used to verify that signature inside of a program.
	// The public key is encoded to Aleo "address" type.
	SignerPubKey string

	// Information about the SGX. Exists only when ReportType is "sgx"
	SgxInfo *SgxInfo
}

Contains information about the TEE enclave that the Notarization Backend is running in

func (*EnclaveInfo) UnmarshalJSON

func (e *EnclaveInfo) UnmarshalJSON(b []byte) error

type EnclaveInfoOptions

type EnclaveInfoOptions struct {
	// Optional enclave information request context. If not provided, uses a context with timeout of 5s.
	Context context.Context
}

GetEnclavesInfo options.

type EncodingOptions

type EncodingOptions struct {
	// Defines how Notarization Backend should interpret the Attestation Data to encode it to Aleo format.
	Value EncodingOptionsValueType

	// Aleo program encoding precision of the Attestation Data when interpreting as float and encoding it to Aleo format.
	// Must be equal or bigger than the number of digits after the comma. Maximum is 12.
	//
	// Required if Value is ENCODING_OPTIONS_VALUE_FLOAT
	//
	// Precision should always be bigger or equal to the number of digits in the fractional part of the extracted number.
	// If the number has more digits in the fractional part than the provided precision, it will be sliced to the provided precision.
	//
	// With Precision=3, the slicing examples:
	//   - 123.456 -> 123.456
	//   - 123.45 -> 123.45
	//   - 123.4567 -> 123.456
	//
	// With Precision=0, the slicing examples:
	//   - 123.456 -> 123
	//   - 123.45 -> 123
	//   - 123.4567 -> 123
	Precision int
}

EncodingOptions is a type containing information about how Notarization Backend should interpret the Attestation Data to encode it to Aleo format. Data will be encoded to Aleo "u128" to allow for usage inside of Aleo programs.

type EncodingOptionsValueType

type EncodingOptionsValueType string

The expected type of value that should be used to interpret Attestation Data to encode it to Aleo format (to be used in an Aleo program).

const (
	ENCODING_OPTIONS_VALUE_STRING EncodingOptionsValueType = "string" // Extracted value is interpretted as a string
	ENCODING_OPTIONS_VALUE_FLOAT  EncodingOptionsValueType = "float"  // Extracted value is interpreted as a positive floating point number up to 64 bits in size
	ENCODING_OPTIONS_VALUE_INT    EncodingOptionsValueType = "int"    // Extracted value is interpreted as an unsigned decimal integer up to 64 bits in size
)

Available options for EncodingOptionsValueType

type HtmlResultType

type HtmlResultType string

Type of value extraction on a HTML element after applying a selector.

const (
	HTML_RESULT_TYPE_ELEMENT HtmlResultType = "element" // will extract "<a href="/test">Nice link</a>"
	HTML_RESULT_TYPE_VALUE   HtmlResultType = "value"   // will extract "Nice link"
)

Available options for HTML result type. Given a selected HTML element

<a href="/test">Nice link</a>

type NotarizationOptions

type NotarizationOptions struct {
	// Optional attestation request context. If not provided, uses a context with timeout of 5s.
	AttestationContext context.Context

	// Optional verification request context. If not provided, uses a context with timeout of 5s.
	VerificationContext context.Context

	// If multiple attesters are used, the client will check that the attestation data is exactly the same in all attestation responses.
	DataShouldMatch bool

	// If multiple attesters are used this option controls the maximum deviation in milliseconds between attestation timestamps.
	//
	// 	- if set to 0, requires that all attestations are done at the same time (not recommended). Note that the attestation timestamp
	// is set by the attestation server using server time.
	// 	- if nil, no time deviation checks are performed.
	//  - if time deviation is set to less then a second, attestation might fail due to naturally occuring network delays between the Oracle SDK, the notarization backends, and the attestation target.
	//  - if deviation is set to more than 10 seconds (10 * 1000 ms), the attestation target responses might differ from each other because one of the requests took too long, and the requested information either has changed or is not available anymore.
	MaxTimeDeviation *int64
}

NotarizationOptions contains ptional parameters that you can provide to Notarize method.

If not provided, default values will be used.

type OracleData

type OracleData struct {
	// Schnorr signature of a verified Attestation Report.
	Signature string `json:"signature"`

	// Aleo-encoded data that was used to create the hash included in the Attestation Report.
	//
	// See ProofPositionalInfo for an idea of what data goes into the hash.
	UserData string `json:"userData"`

	// Aleo-encoded Attestation Report.
	Report string `json:"report"`

	// Public key the signature was created against.
	Address string `json:"address"`

	// Object containing information about the positions of data included in the Attestation Report hash.
	EncodedPositions ProofPositionalInfo `json:"encodedPositions"`

	// Aleo-encoded request. Same as UserData but with zeroed Data and Timestamp fields. Can be used to validate the request in Aleo programs.
	//
	// Data and Timestamp are the only parts of UserData that can be different every time you do a notarization request.
	// By zeroing out these 2 fields, we can create a constant UserData which is going to represent a request to the attestation target.
	// When an Aleo program is going to verify that a request was done using the correct parameters, like URL, request body, request headers etc.,
	// it can take the UserData provided with the Attestation Report, replace Data and Timestamp with "0u128" and then compare the result with the constant UserData in the program.
	// If both UserDatas match, then we know that the Attestation Report was made using the correct attestation target request!
	//
	// To avoid storing the full UserData in an Aleo program, we can hash it and store only the hash in the program. See RequestHash.
	EncodedRequest string `json:"encodedRequest"`

	// Poseidon8 hash of the EncodedRequest. Can be used to verify in an Aleo program that the report was made with the correct request.
	RequestHash string `json:"requestHash"`
}

OracleData contains information that can be used in your Aleo program. All fields are encoded to Aleo-compatible formats and represented as strings.

type PositionInfo

type PositionInfo struct {
	// Index of the block where the write operation started. Indexing starts from 0. Note that this number doesn't account the fact that each chunk contains 32 blocks.
	//
	// If Pos is >32, it means that there was an "overflow" to the next chunk of 32 blocks, e.g. Pos 31 means chunk 0 field 31, Pos 32 means chunk 1, field 0.
	Pos int

	// Number of blocks written in the write operation.
	Len int
}

PositionInfo contains extra information about the way attestation response was encoded for Aleo. Useful in development to find the positions of different response elements for Aleo program development.

type ProofPositionalInfo

type ProofPositionalInfo struct {
	Data            PositionInfo `json:"data"`
	Timestamp       PositionInfo `json:"timestamp"`
	StatusCode      PositionInfo `json:"statusCode"`
	Method          PositionInfo `json:"method"`
	ResponseFormat  PositionInfo `json:"responseFormat"`
	Url             PositionInfo `json:"url"`
	Selector        PositionInfo `json:"selector"`
	EncodingOptions PositionInfo `json:"encodingOptions"`
	RequestHeaders  PositionInfo `json:"requestHeaders"`
	OptionalFields  PositionInfo `json:"optionalFields"` // Optional fields are HTML result type, request content type, request body. They're all encoded together.
}

ProofPositionalInfo is an object containing information about the positions of data included in the Attestation Report hash. This object is created to help developers understand how to extract fields to verify or use them in Aleo programs.

No element will occupy positions 0 and 1. Positions 0 and 1 in OracleData.UserData are reserved for information about data positioning, i.e. meta header (which can be used later to decode and verify OracleData.UserData).

type ResponseFormat

type ResponseFormat string

Attestation target response format

const (
	RESPONSE_FORMAT_JSON ResponseFormat = "json"
	RESPONSE_FORMAT_HTML ResponseFormat = "html"
)

Available options for ResponseFormat

type SgxInfo

type SgxInfo struct {
	SecurityVersion uint      `json:"securityVersion"` // Security version of the enclave. For SGX enclaves, this is the ISVSVN value.
	Debug           bool      `json:"debug"`           // If true, the report is for a debug enclave.
	UniqueID        []byte    `json:"uniqueId"`        // The unique ID for the enclave. For SGX enclaves, this is the MRENCLAVE value.
	AleoUniqueID    [2]string `json:"aleoUniqueId"`    // Same as UniqueID but encoded for Aleo as 2 uint128
	SignerID        []byte    `json:"signerId"`        // The signer ID for the enclave. For SGX enclaves, this is the MRSIGNER value.
	AleoSignerID    [2]string `json:"aleoSignerId"`    // Same as SignerID but encoded for Aleo as 2 uint128
	ProductID       []byte    `json:"productId"`       // The Product ID for the enclave. For SGX enclaves, this is the ISVPRODID value.
	AleoProductID   string    `json:"aleoProductId"`   // Same as ProductID but encoded for Aleo as 1 uint128
	TCBStatus       uint      `json:"tcbStatus"`       // The status of the enclave's TCB level.
}

Contains information about an SGX enclave.

type TestSelectorOptions

type TestSelectorOptions struct {
	Context context.Context
}

TestSelector method options.

type TestSelectorResponse

type TestSelectorResponse struct {
	// URL of the Notarization Backend the response came from.
	EnclaveUrl string `json:"enclaveUrl"`

	// Full response body received in the attestation target's response
	ResponseBody string `json:"responseBody"`

	// Status code of the attestation target's response
	ResponseStatusCode int `json:"responseStatusCode"`

	// Extracted data from ResponseBody using the provided selector
	ExtractedData string `json:"extractedData"`
}

TestSelector response, which contains information for debugging selectors for extracting AttestationData for calling Notarize.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL